Update module lib/pq to v1.6.0 (#572)
Update module lib/pq to v1.6.0 Reviewed-on: https://kolaente.dev/vikunja/api/pulls/572
This commit is contained in:
parent
5a04f1ecf4
commit
54b18b3c59
161 changed files with 19472 additions and 7 deletions
2
go.mod
2
go.mod
|
@ -44,7 +44,7 @@ require (
|
||||||
github.com/labstack/echo/v4 v4.1.16
|
github.com/labstack/echo/v4 v4.1.16
|
||||||
github.com/labstack/gommon v0.3.0
|
github.com/labstack/gommon v0.3.0
|
||||||
github.com/laurent22/ical-go v0.1.1-0.20181107184520-7e5d6ade8eef
|
github.com/laurent22/ical-go v0.1.1-0.20181107184520-7e5d6ade8eef
|
||||||
github.com/lib/pq v1.5.2
|
github.com/lib/pq v1.6.0
|
||||||
github.com/mailru/easyjson v0.7.0 // indirect
|
github.com/mailru/easyjson v0.7.0 // indirect
|
||||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible
|
github.com/mattn/go-sqlite3 v2.0.3+incompatible
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
|
||||||
|
|
28
go.sum
28
go.sum
|
@ -47,6 +47,8 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafo
|
||||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
|
github.com/alexbrainman/sspi v0.0.0-20180613141037-e580b900e9f5 h1:P5U+E4x5OkVEKQDklVPmzs71WM56RTTRqV4OrDC//Y4=
|
||||||
|
github.com/alexbrainman/sspi v0.0.0-20180613141037-e580b900e9f5/go.mod h1:976q2ETgjT2snVCf2ZaBnyBbVoPERGjUz+0sofzEfro=
|
||||||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||||
|
@ -211,6 +213,8 @@ github.com/gordonklaus/ineffassign v0.0.0-20200309095847-7953dde2c7bf h1:vc7Dmrk
|
||||||
github.com/gordonklaus/ineffassign v0.0.0-20200309095847-7953dde2c7bf/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU=
|
github.com/gordonklaus/ineffassign v0.0.0-20200309095847-7953dde2c7bf/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU=
|
||||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||||
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||||
|
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
||||||
|
github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
|
||||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||||
|
@ -228,6 +232,8 @@ github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerX
|
||||||
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
|
github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE=
|
||||||
|
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
|
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
|
||||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
|
@ -246,6 +252,18 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt
|
||||||
github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 h1:vr3AYkKovP8uR8AvSGGUK1IDqRa5lAAvEkZG1LKaCRc=
|
github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 h1:vr3AYkKovP8uR8AvSGGUK1IDqRa5lAAvEkZG1LKaCRc=
|
||||||
github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ=
|
github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ=
|
||||||
github.com/jackc/pgx v3.6.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
|
github.com/jackc/pgx v3.6.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
|
||||||
|
github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8=
|
||||||
|
github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs=
|
||||||
|
github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo=
|
||||||
|
github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM=
|
||||||
|
github.com/jcmturner/gofork v1.0.0 h1:J7uCkflzTEhUZ64xqKnkDxq3kzc96ajM1Gli5ktUem8=
|
||||||
|
github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o=
|
||||||
|
github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o=
|
||||||
|
github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg=
|
||||||
|
github.com/jcmturner/gokrb5/v8 v8.2.0 h1:lzPl/30ZLkTveYsYZPKMcgXc8MbnE6RsTd4F9KgiLtk=
|
||||||
|
github.com/jcmturner/gokrb5/v8 v8.2.0/go.mod h1:T1hnNppQsBtxW0tCHMHTkAt8n/sABdzZgZdoFrZaZNM=
|
||||||
|
github.com/jcmturner/rpc/v2 v2.0.2 h1:gMB4IwRXYsWw4Bc6o/az2HJgFUA1ffSh90i26ZJ6Xl0=
|
||||||
|
github.com/jcmturner/rpc/v2 v2.0.2/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
|
||||||
github.com/jeffbean/tail v1.0.1 h1:mRuCwa9iq5kH1SBFAIWWFsg+NEi5+VVEf2E2ORVkKp8=
|
github.com/jeffbean/tail v1.0.1 h1:mRuCwa9iq5kH1SBFAIWWFsg+NEi5+VVEf2E2ORVkKp8=
|
||||||
github.com/jeffbean/tail v1.0.1/go.mod h1:+MhJ+VPZMpv8Ui6WRzpJFuWFKxBCZgVOo5HAmlw1sFc=
|
github.com/jeffbean/tail v1.0.1/go.mod h1:+MhJ+VPZMpv8Ui6WRzpJFuWFKxBCZgVOo5HAmlw1sFc=
|
||||||
github.com/jgautheron/goconst v0.0.0-20200227150835-cda7ea3bf591 h1:x/BpEhm6aL26o4TLtcU0loJ7B3+69jielrGc70V7Yb4=
|
github.com/jgautheron/goconst v0.0.0-20200227150835-cda7ea3bf591 h1:x/BpEhm6aL26o4TLtcU0loJ7B3+69jielrGc70V7Yb4=
|
||||||
|
@ -296,6 +314,8 @@ github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU=
|
||||||
github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||||
github.com/lib/pq v1.5.2 h1:yTSXVswvWUOQ3k1sd7vJfDrbSl8lKuscqFJRqjC0ifw=
|
github.com/lib/pq v1.5.2 h1:yTSXVswvWUOQ3k1sd7vJfDrbSl8lKuscqFJRqjC0ifw=
|
||||||
github.com/lib/pq v1.5.2/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
github.com/lib/pq v1.5.2/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||||
|
github.com/lib/pq v1.6.0 h1:I5DPxhYJChW9KYc66se+oKFFQX6VuQrKiprsX6ivRZc=
|
||||||
|
github.com/lib/pq v1.6.0/go.mod h1:4vXEAYvW1fRQ2/FhZ78H73A60MHw1geSm145z2mdY1g=
|
||||||
github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
|
github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
|
||||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
|
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
|
||||||
|
@ -523,7 +543,9 @@ golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8U
|
||||||
golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4 h1:ydJNl0ENAG67pFbB+9tfhiL2pYqLhfoaZFw/cjLhY4A=
|
golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4 h1:ydJNl0ENAG67pFbB+9tfhiL2pYqLhfoaZFw/cjLhY4A=
|
||||||
golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20200117160349-530e935923ad/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 h1:cg5LA/zNPRzIXIWSCxQW10Rvpy94aQh3LT/ShoCpkHw=
|
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 h1:cg5LA/zNPRzIXIWSCxQW10Rvpy94aQh3LT/ShoCpkHw=
|
||||||
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
|
@ -575,6 +597,7 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwL
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b h1:0mm1VjtFUOIlE1SbDlwjYaDxZVDP2S5ou6y0gSgXHu8=
|
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b h1:0mm1VjtFUOIlE1SbDlwjYaDxZVDP2S5ou6y0gSgXHu8=
|
||||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k=
|
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k=
|
||||||
|
@ -722,6 +745,11 @@ gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AW
|
||||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
|
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
|
||||||
gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
|
gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
|
||||||
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
|
gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo=
|
||||||
|
gopkg.in/jcmturner/dnsutils.v1 v1.0.1/go.mod h1:m3v+5svpVOhtFAP/wSz+yzh4Mc0Fg7eRhxkJMWSIz9Q=
|
||||||
|
gopkg.in/jcmturner/goidentity.v3 v3.0.0/go.mod h1:oG2kH0IvSYNIu80dVAyu/yoefjq1mNfM5bm88whjWx4=
|
||||||
|
gopkg.in/jcmturner/gokrb5.v7 v7.5.0/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM=
|
||||||
|
gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLvuNnlv8=
|
||||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||||
|
|
27
vendor/github.com/alexbrainman/sspi/LICENSE
generated
vendored
Normal file
27
vendor/github.com/alexbrainman/sspi/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
Copyright (c) 2012 The Go Authors. 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 Google Inc. nor the names of its
|
||||||
|
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.
|
1
vendor/github.com/alexbrainman/sspi/README.md
generated
vendored
Normal file
1
vendor/github.com/alexbrainman/sspi/README.md
generated
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
This repository holds Go packages for accessing Security Support Provider Interface on Windows.
|
57
vendor/github.com/alexbrainman/sspi/buffer.go
generated
vendored
Normal file
57
vendor/github.com/alexbrainman/sspi/buffer.go
generated
vendored
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
// Copyright 2015 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package sspi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (b *SecBuffer) Set(buftype uint32, data []byte) {
|
||||||
|
b.BufferType = buftype
|
||||||
|
if len(data) > 0 {
|
||||||
|
b.Buffer = &data[0]
|
||||||
|
b.BufferSize = uint32(len(data))
|
||||||
|
} else {
|
||||||
|
b.Buffer = nil
|
||||||
|
b.BufferSize = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *SecBuffer) Free() error {
|
||||||
|
if b.Buffer == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return FreeContextBuffer((*byte)(unsafe.Pointer(b.Buffer)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *SecBuffer) Bytes() []byte {
|
||||||
|
if b.Buffer == nil || b.BufferSize <= 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return (*[2 << 20]byte)(unsafe.Pointer(b.Buffer))[:b.BufferSize]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *SecBuffer) WriteAll(w io.Writer) (int, error) {
|
||||||
|
if b.BufferSize == 0 || b.Buffer == nil {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
data := b.Bytes()
|
||||||
|
total := 0
|
||||||
|
for {
|
||||||
|
n, err := w.Write(data)
|
||||||
|
total += n
|
||||||
|
if err != nil {
|
||||||
|
return total, err
|
||||||
|
}
|
||||||
|
if n >= len(data) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
data = data[n:]
|
||||||
|
}
|
||||||
|
return total, nil
|
||||||
|
}
|
7
vendor/github.com/alexbrainman/sspi/mksyscall.go
generated
vendored
Normal file
7
vendor/github.com/alexbrainman/sspi/mksyscall.go
generated
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package sspi
|
||||||
|
|
||||||
|
//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -systemdll=false -output=zsyscall_windows.go syscall.go
|
462
vendor/github.com/alexbrainman/sspi/negotiate/negotiate.go
generated
vendored
Normal file
462
vendor/github.com/alexbrainman/sspi/negotiate/negotiate.go
generated
vendored
Normal file
|
@ -0,0 +1,462 @@
|
||||||
|
// Copyright 2016 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
// Package negotiate provides access to the Microsoft Negotiate SSP Package.
|
||||||
|
//
|
||||||
|
package negotiate
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/alexbrainman/sspi"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO: maybe (if possible) move all winapi related out of sspi and into sspi/internal/winapi
|
||||||
|
|
||||||
|
// PackageInfo contains Negotiate SSP package description.
|
||||||
|
var PackageInfo *sspi.PackageInfo
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
var err error
|
||||||
|
PackageInfo, err = sspi.QueryPackageInfo(sspi.NEGOSSP_NAME)
|
||||||
|
if err != nil {
|
||||||
|
panic("failed to fetch Negotiate package info: " + err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func acquireCredentials(principalName string, creduse uint32, ai *sspi.SEC_WINNT_AUTH_IDENTITY) (*sspi.Credentials, error) {
|
||||||
|
c, err := sspi.AcquireCredentials(principalName, sspi.NEGOSSP_NAME, creduse, (*byte)(unsafe.Pointer(ai)))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AcquireCurrentUserCredentials acquires credentials of currently
|
||||||
|
// logged on user. These will be used by the client to authenticate
|
||||||
|
// itself to the server. It will also be used by the server
|
||||||
|
// to impersonate the user.
|
||||||
|
func AcquireCurrentUserCredentials() (*sspi.Credentials, error) {
|
||||||
|
return acquireCredentials("", sspi.SECPKG_CRED_OUTBOUND, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: see if I can share this common ntlm and negotiate code
|
||||||
|
|
||||||
|
// AcquireUserCredentials acquires credentials of user described by
|
||||||
|
// domain, username and password. These will be used by the client to
|
||||||
|
// authenticate itself to the server. It will also be used by the
|
||||||
|
// server to impersonate the user.
|
||||||
|
func AcquireUserCredentials(domain, username, password string) (*sspi.Credentials, error) {
|
||||||
|
if len(username) == 0 {
|
||||||
|
return nil, errors.New("username parameter cannot be empty")
|
||||||
|
}
|
||||||
|
d, err := syscall.UTF16FromString(domain)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
u, err := syscall.UTF16FromString(username)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
p, err := syscall.UTF16FromString(password)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ai := sspi.SEC_WINNT_AUTH_IDENTITY{
|
||||||
|
User: &u[0],
|
||||||
|
UserLength: uint32(len(u) - 1), // do not count terminating 0
|
||||||
|
Domain: &d[0],
|
||||||
|
DomainLength: uint32(len(d) - 1), // do not count terminating 0
|
||||||
|
Password: &p[0],
|
||||||
|
PasswordLength: uint32(len(p) - 1), // do not count terminating 0
|
||||||
|
Flags: sspi.SEC_WINNT_AUTH_IDENTITY_UNICODE,
|
||||||
|
}
|
||||||
|
return acquireCredentials("", sspi.SECPKG_CRED_OUTBOUND, &ai)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AcquireServerCredentials acquires server credentials that will
|
||||||
|
// be used to authenticate clients.
|
||||||
|
// The principalName parameter is passed to the underlying call to
|
||||||
|
// the winapi AcquireCredentialsHandle function (and specifies the
|
||||||
|
// name of the principal whose credentials the underlying handle
|
||||||
|
// will reference).
|
||||||
|
// As a special case, using an empty string for the principal name
|
||||||
|
// will require the credential of the user under whose security context
|
||||||
|
// the current process is running.
|
||||||
|
func AcquireServerCredentials(principalName string) (*sspi.Credentials, error) {
|
||||||
|
return acquireCredentials(principalName, sspi.SECPKG_CRED_INBOUND, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateContext(c *sspi.Context, dst, src []byte, targetName *uint16) (authCompleted bool, n int, err error) {
|
||||||
|
var inBuf, outBuf [1]sspi.SecBuffer
|
||||||
|
inBuf[0].Set(sspi.SECBUFFER_TOKEN, src)
|
||||||
|
inBufs := &sspi.SecBufferDesc{
|
||||||
|
Version: sspi.SECBUFFER_VERSION,
|
||||||
|
BuffersCount: 1,
|
||||||
|
Buffers: &inBuf[0],
|
||||||
|
}
|
||||||
|
outBuf[0].Set(sspi.SECBUFFER_TOKEN, dst)
|
||||||
|
outBufs := &sspi.SecBufferDesc{
|
||||||
|
Version: sspi.SECBUFFER_VERSION,
|
||||||
|
BuffersCount: 1,
|
||||||
|
Buffers: &outBuf[0],
|
||||||
|
}
|
||||||
|
ret := c.Update(targetName, outBufs, inBufs)
|
||||||
|
switch ret {
|
||||||
|
case sspi.SEC_E_OK:
|
||||||
|
// session established -> return success
|
||||||
|
return true, int(outBuf[0].BufferSize), nil
|
||||||
|
case sspi.SEC_I_COMPLETE_NEEDED, sspi.SEC_I_COMPLETE_AND_CONTINUE:
|
||||||
|
ret = sspi.CompleteAuthToken(c.Handle, outBufs)
|
||||||
|
if ret != sspi.SEC_E_OK {
|
||||||
|
return false, 0, ret
|
||||||
|
}
|
||||||
|
case sspi.SEC_I_CONTINUE_NEEDED:
|
||||||
|
default:
|
||||||
|
return false, 0, ret
|
||||||
|
}
|
||||||
|
return false, int(outBuf[0].BufferSize), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeSignature(c *sspi.Context, msg []byte, qop, seqno uint32) ([]byte, error) {
|
||||||
|
_, maxSignature, _, _, err := c.Sizes()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if maxSignature == 0 {
|
||||||
|
return nil, errors.New("integrity services are not requested or unavailable")
|
||||||
|
}
|
||||||
|
|
||||||
|
var b [2]sspi.SecBuffer
|
||||||
|
b[0].Set(sspi.SECBUFFER_DATA, msg)
|
||||||
|
b[1].Set(sspi.SECBUFFER_TOKEN, make([]byte, maxSignature))
|
||||||
|
|
||||||
|
ret := sspi.MakeSignature(c.Handle, qop, sspi.NewSecBufferDesc(b[:]), seqno)
|
||||||
|
if ret != sspi.SEC_E_OK {
|
||||||
|
return nil, ret
|
||||||
|
}
|
||||||
|
|
||||||
|
return b[1].Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func encryptMessage(c *sspi.Context, msg []byte, qop, seqno uint32) ([]byte, error) {
|
||||||
|
_ /*maxToken*/, maxSignature, cBlockSize, cSecurityTrailer, err := c.Sizes()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if maxSignature == 0 {
|
||||||
|
return nil, errors.New("integrity services are not requested or unavailable")
|
||||||
|
}
|
||||||
|
|
||||||
|
var b [3]sspi.SecBuffer
|
||||||
|
b[0].Set(sspi.SECBUFFER_TOKEN, make([]byte, cSecurityTrailer))
|
||||||
|
b[1].Set(sspi.SECBUFFER_DATA, msg)
|
||||||
|
b[2].Set(sspi.SECBUFFER_PADDING, make([]byte, cBlockSize))
|
||||||
|
|
||||||
|
ret := sspi.EncryptMessage(c.Handle, qop, sspi.NewSecBufferDesc(b[:]), seqno)
|
||||||
|
if ret != sspi.SEC_E_OK {
|
||||||
|
return nil, ret
|
||||||
|
}
|
||||||
|
|
||||||
|
r0, r1, r2 := b[0].Bytes(), b[1].Bytes(), b[2].Bytes()
|
||||||
|
res := make([]byte, 0, len(r0)+len(r1)+len(r2))
|
||||||
|
res = append(res, r0...)
|
||||||
|
res = append(res, r1...)
|
||||||
|
res = append(res, r2...)
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func decryptMessage(c *sspi.Context, msg []byte, seqno uint32) (uint32, []byte, error) {
|
||||||
|
var b [2]sspi.SecBuffer
|
||||||
|
b[0].Set(sspi.SECBUFFER_STREAM, msg)
|
||||||
|
b[1].Set(sspi.SECBUFFER_DATA, []byte{})
|
||||||
|
|
||||||
|
var qop uint32
|
||||||
|
ret := sspi.DecryptMessage(c.Handle, sspi.NewSecBufferDesc(b[:]), seqno, &qop)
|
||||||
|
if ret != sspi.SEC_E_OK {
|
||||||
|
return qop, nil, ret
|
||||||
|
}
|
||||||
|
|
||||||
|
return qop, b[1].Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func verifySignature(c *sspi.Context, msg, token []byte, seqno uint32) (uint32, error) {
|
||||||
|
var b [2]sspi.SecBuffer
|
||||||
|
b[0].Set(sspi.SECBUFFER_DATA, msg)
|
||||||
|
b[1].Set(sspi.SECBUFFER_TOKEN, token)
|
||||||
|
|
||||||
|
var qop uint32
|
||||||
|
|
||||||
|
ret := sspi.VerifySignature(c.Handle, sspi.NewSecBufferDesc(b[:]), seqno, &qop)
|
||||||
|
if ret != sspi.SEC_E_OK {
|
||||||
|
return 0, ret
|
||||||
|
}
|
||||||
|
|
||||||
|
return qop, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClientContext is used by the client to manage all steps of Negotiate negotiation.
|
||||||
|
type ClientContext struct {
|
||||||
|
sctxt *sspi.Context
|
||||||
|
targetName *uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewClientContext creates a new client context. It uses client
|
||||||
|
// credentials cred generated by AcquireCurrentUserCredentials or
|
||||||
|
// AcquireUserCredentials and SPN to start a client Negotiate
|
||||||
|
// negotiation sequence. targetName is the service principal name
|
||||||
|
// (SPN) or the security context of the destination server.
|
||||||
|
// NewClientContext returns a new token to be sent to the server.
|
||||||
|
func NewClientContext(cred *sspi.Credentials, targetName string) (cc *ClientContext, outputToken []byte, err error) {
|
||||||
|
return NewClientContextWithFlags(cred, targetName, sspi.ISC_REQ_CONNECTION)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewClientContextWithFlags creates a new client context. It uses client
|
||||||
|
// credentials cred generated by AcquireCurrentUserCredentials or
|
||||||
|
// AcquireUserCredentials and SPN to start a client Negotiate
|
||||||
|
// negotiation sequence. targetName is the service principal name
|
||||||
|
// (SPN) or the security context of the destination server.
|
||||||
|
// The flags parameter is used to indicate requests for the context
|
||||||
|
// (for example sspi.ISC_REQ_CONFIDENTIALITY|sspi.ISC_REQ_REPLAY_DETECT)
|
||||||
|
// NewClientContextWithFlags returns a new token to be sent to the server.
|
||||||
|
func NewClientContextWithFlags(cred *sspi.Credentials, targetName string, flags uint32) (cc *ClientContext, outputToken []byte, err error) {
|
||||||
|
var tname *uint16
|
||||||
|
if len(targetName) > 0 {
|
||||||
|
p, err2 := syscall.UTF16FromString(targetName)
|
||||||
|
if err2 != nil {
|
||||||
|
return nil, nil, err2
|
||||||
|
}
|
||||||
|
if len(p) > 0 {
|
||||||
|
tname = &p[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
otoken := make([]byte, PackageInfo.MaxToken)
|
||||||
|
c := sspi.NewClientContext(cred, flags)
|
||||||
|
|
||||||
|
authCompleted, n, err2 := updateContext(c, otoken, nil, tname)
|
||||||
|
if err2 != nil {
|
||||||
|
return nil, nil, err2
|
||||||
|
}
|
||||||
|
if authCompleted {
|
||||||
|
c.Release()
|
||||||
|
return nil, nil, errors.New("negotiate authentication should not be completed yet")
|
||||||
|
}
|
||||||
|
if n == 0 {
|
||||||
|
c.Release()
|
||||||
|
return nil, nil, errors.New("negotiate token should not be empty")
|
||||||
|
}
|
||||||
|
otoken = otoken[:n]
|
||||||
|
return &ClientContext{sctxt: c, targetName: tname}, otoken, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release free up resources associated with client context c.
|
||||||
|
func (c *ClientContext) Release() error {
|
||||||
|
if c == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return c.sctxt.Release()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expiry returns c expiry time.
|
||||||
|
func (c *ClientContext) Expiry() time.Time {
|
||||||
|
return c.sctxt.Expiry()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update advances client part of Negotiate negotiation c. It uses
|
||||||
|
// token received from the server and returns true if client part
|
||||||
|
// of authentication is complete. It also returns new token to be
|
||||||
|
// sent to the server.
|
||||||
|
func (c *ClientContext) Update(token []byte) (authCompleted bool, outputToken []byte, err error) {
|
||||||
|
otoken := make([]byte, PackageInfo.MaxToken)
|
||||||
|
authDone, n, err2 := updateContext(c.sctxt, otoken, token, c.targetName)
|
||||||
|
if err2 != nil {
|
||||||
|
return false, nil, err2
|
||||||
|
}
|
||||||
|
if n == 0 && !authDone {
|
||||||
|
return false, nil, errors.New("negotiate token should not be empty")
|
||||||
|
}
|
||||||
|
otoken = otoken[:n]
|
||||||
|
return authDone, otoken, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sizes queries the client context for the sizes used in per-message
|
||||||
|
// functions. It returns the maximum token size used in authentication
|
||||||
|
// exchanges, the maximum signature size, the preferred integral size of
|
||||||
|
// messages, the size of any security trailer, and any error.
|
||||||
|
func (c *ClientContext) Sizes() (uint32, uint32, uint32, uint32, error) {
|
||||||
|
return c.sctxt.Sizes()
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeSignature uses the established client context to create a signature
|
||||||
|
// for the given message using the provided quality of protection flags and
|
||||||
|
// sequence number. It returns the signature token in addition to any error.
|
||||||
|
func (c *ClientContext) MakeSignature(msg []byte, qop, seqno uint32) ([]byte, error) {
|
||||||
|
return makeSignature(c.sctxt, msg, qop, seqno)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifySignature uses the established client context and signature token
|
||||||
|
// to check that the provided message hasn't been tampered or received out
|
||||||
|
// of sequence. It returns any quality of protection flags and any error
|
||||||
|
// that occurred.
|
||||||
|
func (c *ClientContext) VerifySignature(msg, token []byte, seqno uint32) (uint32, error) {
|
||||||
|
return verifySignature(c.sctxt, msg, token, seqno)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncryptMessage uses the established client context to encrypt a message
|
||||||
|
// using the provided quality of protection flags and sequence number.
|
||||||
|
// It returns the signature token in addition to any error.
|
||||||
|
// IMPORTANT: the input msg parameter is updated in place by the low-level windows api
|
||||||
|
// so must be copied if the initial content should not be modified.
|
||||||
|
func (c *ClientContext) EncryptMessage(msg []byte, qop, seqno uint32) ([]byte, error) {
|
||||||
|
return encryptMessage(c.sctxt, msg, qop, seqno)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecryptMessage uses the established client context to decrypt a message
|
||||||
|
// using the provided sequence number.
|
||||||
|
// It returns the quality of protection flag and the decrypted message in addition to any error.
|
||||||
|
func (c *ClientContext) DecryptMessage(msg []byte, seqno uint32) (uint32, []byte, error) {
|
||||||
|
return decryptMessage(c.sctxt, msg, seqno)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyFlags determines if all flags used to construct the client context
|
||||||
|
// were honored (see NewClientContextWithFlags). It should be called after c.Update.
|
||||||
|
func (c *ClientContext) VerifyFlags() error {
|
||||||
|
return c.sctxt.VerifyFlags()
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifySelectiveFlags determines if the given flags were honored (see NewClientContextWithFlags).
|
||||||
|
// It should be called after c.Update.
|
||||||
|
func (c *ClientContext) VerifySelectiveFlags(flags uint32) error {
|
||||||
|
return c.sctxt.VerifySelectiveFlags(flags)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServerContext is used by the server to manage all steps of Negotiate
|
||||||
|
// negotiation. Once authentication is completed the context can be
|
||||||
|
// used to impersonate client.
|
||||||
|
type ServerContext struct {
|
||||||
|
sctxt *sspi.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewServerContext creates new server context. It uses server
|
||||||
|
// credentials created by AcquireServerCredentials and token from
|
||||||
|
// the client to start server Negotiate negotiation sequence.
|
||||||
|
// It also returns new token to be sent to the client.
|
||||||
|
func NewServerContext(cred *sspi.Credentials, token []byte) (sc *ServerContext, authDone bool, outputToken []byte, err error) {
|
||||||
|
otoken := make([]byte, PackageInfo.MaxToken)
|
||||||
|
c := sspi.NewServerContext(cred, sspi.ASC_REQ_CONNECTION)
|
||||||
|
authDone, n, err2 := updateContext(c, otoken, token, nil)
|
||||||
|
if err2 != nil {
|
||||||
|
return nil, false, nil, err2
|
||||||
|
}
|
||||||
|
otoken = otoken[:n]
|
||||||
|
return &ServerContext{sctxt: c}, authDone, otoken, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release free up resources associated with server context c.
|
||||||
|
func (c *ServerContext) Release() error {
|
||||||
|
if c == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return c.sctxt.Release()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expiry returns c expiry time.
|
||||||
|
func (c *ServerContext) Expiry() time.Time {
|
||||||
|
return c.sctxt.Expiry()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update advances server part of Negotiate negotiation c. It uses
|
||||||
|
// token received from the client and returns true if server part
|
||||||
|
// of authentication is complete. It also returns new token to be
|
||||||
|
// sent to the client.
|
||||||
|
func (c *ServerContext) Update(token []byte) (authCompleted bool, outputToken []byte, err error) {
|
||||||
|
otoken := make([]byte, PackageInfo.MaxToken)
|
||||||
|
authDone, n, err2 := updateContext(c.sctxt, otoken, token, nil)
|
||||||
|
if err2 != nil {
|
||||||
|
return false, nil, err2
|
||||||
|
}
|
||||||
|
if n == 0 && !authDone {
|
||||||
|
return false, nil, errors.New("negotiate token should not be empty")
|
||||||
|
}
|
||||||
|
otoken = otoken[:n]
|
||||||
|
return authDone, otoken, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const _SECPKG_ATTR_NATIVE_NAMES = 13
|
||||||
|
|
||||||
|
type _SecPkgContext_NativeNames struct {
|
||||||
|
ClientName *uint16
|
||||||
|
ServerName *uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUsername returns the username corresponding to the authenticated client
|
||||||
|
func (c *ServerContext) GetUsername() (string, error) {
|
||||||
|
var ns _SecPkgContext_NativeNames
|
||||||
|
ret := sspi.QueryContextAttributes(c.sctxt.Handle, _SECPKG_ATTR_NATIVE_NAMES, (*byte)(unsafe.Pointer(&ns)))
|
||||||
|
if ret != sspi.SEC_E_OK {
|
||||||
|
return "", ret
|
||||||
|
}
|
||||||
|
sspi.FreeContextBuffer((*byte)(unsafe.Pointer(ns.ServerName)))
|
||||||
|
defer sspi.FreeContextBuffer((*byte)(unsafe.Pointer(ns.ClientName)))
|
||||||
|
return syscall.UTF16ToString((*[2 << 20]uint16)(unsafe.Pointer(ns.ClientName))[:]), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImpersonateUser changes current OS thread user. New user is
|
||||||
|
// the user as specified by client credentials.
|
||||||
|
func (c *ServerContext) ImpersonateUser() error {
|
||||||
|
return c.sctxt.ImpersonateUser()
|
||||||
|
}
|
||||||
|
|
||||||
|
// RevertToSelf stops impersonation. It changes current OS thread
|
||||||
|
// user to what it was before ImpersonateUser was executed.
|
||||||
|
func (c *ServerContext) RevertToSelf() error {
|
||||||
|
return c.sctxt.RevertToSelf()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sizes queries the server context for the sizes used in per-message
|
||||||
|
// functions. It returns the maximum token size used in authentication
|
||||||
|
// exchanges, the maximum signature size, the preferred integral size of
|
||||||
|
// messages, the size of any security trailer, and any error.
|
||||||
|
func (c *ServerContext) Sizes() (uint32, uint32, uint32, uint32, error) {
|
||||||
|
return c.sctxt.Sizes()
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeSignature uses the established server context to create a signature
|
||||||
|
// for the given message using the provided quality of protection flags and
|
||||||
|
// sequence number. It returns the signature token in addition to any error.
|
||||||
|
func (c *ServerContext) MakeSignature(msg []byte, qop, seqno uint32) ([]byte, error) {
|
||||||
|
return makeSignature(c.sctxt, msg, qop, seqno)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifySignature uses the established server context and signature token
|
||||||
|
// to check that the provided message hasn't been tampered or received out
|
||||||
|
// of sequence. It returns any quality of protection flags and any error
|
||||||
|
// that occurred.
|
||||||
|
func (c *ServerContext) VerifySignature(msg, token []byte, seqno uint32) (uint32, error) {
|
||||||
|
return verifySignature(c.sctxt, msg, token, seqno)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncryptMessage uses the established server context to encrypt a message
|
||||||
|
// using the provided quality of protection flags and sequence number.
|
||||||
|
// It returns the signature token in addition to any error.
|
||||||
|
// IMPORTANT: the input msg parameter is updated in place by the low-level windows api
|
||||||
|
// so must be copied if the initial content should not be modified.
|
||||||
|
func (c *ServerContext) EncryptMessage(msg []byte, qop, seqno uint32) ([]byte, error) {
|
||||||
|
return encryptMessage(c.sctxt, msg, qop, seqno)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecryptMessage uses the established server context to decrypt a message
|
||||||
|
// using the provided sequence number.
|
||||||
|
// It returns the quality of protection flag and the decrypted message in addition to any error.
|
||||||
|
func (c *ServerContext) DecryptMessage(msg []byte, seqno uint32) (uint32, []byte, error) {
|
||||||
|
return decryptMessage(c.sctxt, msg, seqno)
|
||||||
|
}
|
226
vendor/github.com/alexbrainman/sspi/sspi.go
generated
vendored
Normal file
226
vendor/github.com/alexbrainman/sspi/sspi.go
generated
vendored
Normal file
|
@ -0,0 +1,226 @@
|
||||||
|
// Copyright 2015 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package sspi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO: add documentation
|
||||||
|
|
||||||
|
type PackageInfo struct {
|
||||||
|
Capabilities uint32
|
||||||
|
Version uint16
|
||||||
|
RPCID uint16
|
||||||
|
MaxToken uint32
|
||||||
|
Name string
|
||||||
|
Comment string
|
||||||
|
}
|
||||||
|
|
||||||
|
func QueryPackageInfo(pkgname string) (*PackageInfo, error) {
|
||||||
|
name, err := syscall.UTF16PtrFromString(pkgname)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var pi *SecPkgInfo
|
||||||
|
ret := QuerySecurityPackageInfo(name, &pi)
|
||||||
|
if ret != SEC_E_OK {
|
||||||
|
return nil, ret
|
||||||
|
}
|
||||||
|
defer FreeContextBuffer((*byte)(unsafe.Pointer(pi)))
|
||||||
|
|
||||||
|
return &PackageInfo{
|
||||||
|
Capabilities: pi.Capabilities,
|
||||||
|
Version: pi.Version,
|
||||||
|
RPCID: pi.RPCID,
|
||||||
|
MaxToken: pi.MaxToken,
|
||||||
|
Name: syscall.UTF16ToString((*[2 << 12]uint16)(unsafe.Pointer(pi.Name))[:]),
|
||||||
|
Comment: syscall.UTF16ToString((*[2 << 12]uint16)(unsafe.Pointer(pi.Comment))[:]),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type Credentials struct {
|
||||||
|
Handle CredHandle
|
||||||
|
expiry syscall.Filetime
|
||||||
|
}
|
||||||
|
|
||||||
|
// AcquireCredentials calls the windows AcquireCredentialsHandle function and
|
||||||
|
// returns Credentials containing a security handle that can be used for
|
||||||
|
// InitializeSecurityContext or AcceptSecurityContext operations.
|
||||||
|
// As a special case, passing an empty string as the principal parameter will
|
||||||
|
// pass a null string to the underlying function.
|
||||||
|
func AcquireCredentials(principal string, pkgname string, creduse uint32, authdata *byte) (*Credentials, error) {
|
||||||
|
var principalName *uint16
|
||||||
|
if principal != "" {
|
||||||
|
var err error
|
||||||
|
principalName, err = syscall.UTF16PtrFromString(principal)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
name, err := syscall.UTF16PtrFromString(pkgname)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var c Credentials
|
||||||
|
ret := AcquireCredentialsHandle(principalName, name, creduse, nil, authdata, 0, 0, &c.Handle, &c.expiry)
|
||||||
|
if ret != SEC_E_OK {
|
||||||
|
return nil, ret
|
||||||
|
}
|
||||||
|
return &c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Credentials) Release() error {
|
||||||
|
if c == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
ret := FreeCredentialsHandle(&c.Handle)
|
||||||
|
if ret != SEC_E_OK {
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Credentials) Expiry() time.Time {
|
||||||
|
return time.Unix(0, c.expiry.Nanoseconds())
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: add functions to display and manage RequestedFlags and EstablishedFlags fields.
|
||||||
|
// TODO: maybe get rid of RequestedFlags and EstablishedFlags fields, and replace them with input parameter for New...Context and return value of Update (instead of current bool parameter).
|
||||||
|
|
||||||
|
type updateFunc func(c *Context, targname *uint16, h, newh *CtxtHandle, out, in *SecBufferDesc) syscall.Errno
|
||||||
|
|
||||||
|
type Context struct {
|
||||||
|
Cred *Credentials
|
||||||
|
Handle *CtxtHandle
|
||||||
|
handle CtxtHandle
|
||||||
|
updFn updateFunc
|
||||||
|
expiry syscall.Filetime
|
||||||
|
RequestedFlags uint32
|
||||||
|
EstablishedFlags uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewClientContext(cred *Credentials, flags uint32) *Context {
|
||||||
|
return &Context{
|
||||||
|
Cred: cred,
|
||||||
|
updFn: initialize,
|
||||||
|
RequestedFlags: flags,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewServerContext(cred *Credentials, flags uint32) *Context {
|
||||||
|
return &Context{
|
||||||
|
Cred: cred,
|
||||||
|
updFn: accept,
|
||||||
|
RequestedFlags: flags,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func initialize(c *Context, targname *uint16, h, newh *CtxtHandle, out, in *SecBufferDesc) syscall.Errno {
|
||||||
|
return InitializeSecurityContext(&c.Cred.Handle, h, targname, c.RequestedFlags,
|
||||||
|
0, SECURITY_NATIVE_DREP, in, 0, newh, out, &c.EstablishedFlags, &c.expiry)
|
||||||
|
}
|
||||||
|
|
||||||
|
func accept(c *Context, targname *uint16, h, newh *CtxtHandle, out, in *SecBufferDesc) syscall.Errno {
|
||||||
|
return AcceptSecurityContext(&c.Cred.Handle, h, in, c.RequestedFlags,
|
||||||
|
SECURITY_NATIVE_DREP, newh, out, &c.EstablishedFlags, &c.expiry)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Context) Update(targname *uint16, out, in *SecBufferDesc) syscall.Errno {
|
||||||
|
h := c.Handle
|
||||||
|
if c.Handle == nil {
|
||||||
|
c.Handle = &c.handle
|
||||||
|
}
|
||||||
|
return c.updFn(c, targname, h, c.Handle, out, in)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Context) Release() error {
|
||||||
|
if c == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
ret := DeleteSecurityContext(c.Handle)
|
||||||
|
if ret != SEC_E_OK {
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Context) Expiry() time.Time {
|
||||||
|
return time.Unix(0, c.expiry.Nanoseconds())
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: add comment to function doco that this "impersonation" is applied to current OS thread.
|
||||||
|
func (c *Context) ImpersonateUser() error {
|
||||||
|
ret := ImpersonateSecurityContext(c.Handle)
|
||||||
|
if ret != SEC_E_OK {
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Context) RevertToSelf() error {
|
||||||
|
ret := RevertSecurityContext(c.Handle)
|
||||||
|
if ret != SEC_E_OK {
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sizes queries the context for the sizes used in per-message functions.
|
||||||
|
// It returns the maximum token size used in authentication exchanges, the
|
||||||
|
// maximum signature size, the preferred integral size of messages, the
|
||||||
|
// size of any security trailer, and any error.
|
||||||
|
func (c *Context) Sizes() (uint32, uint32, uint32, uint32, error) {
|
||||||
|
var s _SecPkgContext_Sizes
|
||||||
|
ret := QueryContextAttributes(c.Handle, _SECPKG_ATTR_SIZES, (*byte)(unsafe.Pointer(&s)))
|
||||||
|
if ret != SEC_E_OK {
|
||||||
|
return 0, 0, 0, 0, ret
|
||||||
|
}
|
||||||
|
return s.MaxToken, s.MaxSignature, s.BlockSize, s.SecurityTrailer, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyFlags determines if all flags used to construct the context
|
||||||
|
// were honored (see NewClientContext). It should be called after c.Update.
|
||||||
|
func (c *Context) VerifyFlags() error {
|
||||||
|
return c.VerifySelectiveFlags(c.RequestedFlags)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifySelectiveFlags determines if the given flags were honored (see NewClientContext).
|
||||||
|
// It should be called after c.Update.
|
||||||
|
func (c *Context) VerifySelectiveFlags(flags uint32) error {
|
||||||
|
if valid, missing, extra := verifySelectiveFlags(flags, c.RequestedFlags); !valid {
|
||||||
|
return fmt.Errorf("sspi: invalid flags check: desired=%b requested=%b missing=%b extra=%b", flags, c.RequestedFlags, missing, extra)
|
||||||
|
}
|
||||||
|
if valid, missing, extra := verifySelectiveFlags(flags, c.EstablishedFlags); !valid {
|
||||||
|
return fmt.Errorf("sspi: invalid flags: desired=%b established=%b missing=%b extra=%b", flags, c.EstablishedFlags, missing, extra)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// verifySelectiveFlags determines if all bits requested in flags are set in establishedFlags.
|
||||||
|
// missing represents the bits set in flags that are not set in establishedFlags.
|
||||||
|
// extra represents the bits set in establishedFlags that are not set in flags.
|
||||||
|
// valid is true and missing is zero when establishedFlags has all of the requested flags.
|
||||||
|
func verifySelectiveFlags(flags, establishedFlags uint32) (valid bool, missing, extra uint32) {
|
||||||
|
missing = flags&establishedFlags ^ flags
|
||||||
|
extra = flags | establishedFlags ^ flags
|
||||||
|
valid = missing == 0
|
||||||
|
return valid, missing, extra
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSecBufferDesc returns an initialized SecBufferDesc describing the
|
||||||
|
// provided SecBuffer.
|
||||||
|
func NewSecBufferDesc(b []SecBuffer) *SecBufferDesc {
|
||||||
|
return &SecBufferDesc{
|
||||||
|
Version: SECBUFFER_VERSION,
|
||||||
|
BuffersCount: uint32(len(b)),
|
||||||
|
Buffers: &b[0],
|
||||||
|
}
|
||||||
|
}
|
174
vendor/github.com/alexbrainman/sspi/syscall.go
generated
vendored
Normal file
174
vendor/github.com/alexbrainman/sspi/syscall.go
generated
vendored
Normal file
|
@ -0,0 +1,174 @@
|
||||||
|
// Copyright 2015 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package sspi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
SEC_E_OK = syscall.Errno(0)
|
||||||
|
|
||||||
|
SEC_I_COMPLETE_AND_CONTINUE = syscall.Errno(590612)
|
||||||
|
SEC_I_COMPLETE_NEEDED = syscall.Errno(590611)
|
||||||
|
SEC_I_CONTINUE_NEEDED = syscall.Errno(590610)
|
||||||
|
|
||||||
|
SEC_E_LOGON_DENIED = syscall.Errno(0x8009030c)
|
||||||
|
SEC_E_CONTEXT_EXPIRED = syscall.Errno(0x80090317) // not sure if the value is valid
|
||||||
|
SEC_E_INCOMPLETE_MESSAGE = syscall.Errno(0x80090318)
|
||||||
|
|
||||||
|
NTLMSP_NAME = "NTLM"
|
||||||
|
MICROSOFT_KERBEROS_NAME = "Kerberos"
|
||||||
|
NEGOSSP_NAME = "Negotiate"
|
||||||
|
UNISP_NAME = "Microsoft Unified Security Protocol Provider"
|
||||||
|
|
||||||
|
_SECPKG_ATTR_SIZES = 0
|
||||||
|
_SECPKG_ATTR_NAMES = 1
|
||||||
|
_SECPKG_ATTR_LIFESPAN = 2
|
||||||
|
_SECPKG_ATTR_DCE_INFO = 3
|
||||||
|
_SECPKG_ATTR_STREAM_SIZES = 4
|
||||||
|
_SECPKG_ATTR_KEY_INFO = 5
|
||||||
|
_SECPKG_ATTR_AUTHORITY = 6
|
||||||
|
_SECPKG_ATTR_PROTO_INFO = 7
|
||||||
|
_SECPKG_ATTR_PASSWORD_EXPIRY = 8
|
||||||
|
_SECPKG_ATTR_SESSION_KEY = 9
|
||||||
|
_SECPKG_ATTR_PACKAGE_INFO = 10
|
||||||
|
_SECPKG_ATTR_USER_FLAGS = 11
|
||||||
|
_SECPKG_ATTR_NEGOTIATION_INFO = 12
|
||||||
|
_SECPKG_ATTR_NATIVE_NAMES = 13
|
||||||
|
_SECPKG_ATTR_FLAGS = 14
|
||||||
|
)
|
||||||
|
|
||||||
|
type SecPkgInfo struct {
|
||||||
|
Capabilities uint32
|
||||||
|
Version uint16
|
||||||
|
RPCID uint16
|
||||||
|
MaxToken uint32
|
||||||
|
Name *uint16
|
||||||
|
Comment *uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
type _SecPkgContext_Sizes struct {
|
||||||
|
MaxToken uint32
|
||||||
|
MaxSignature uint32
|
||||||
|
BlockSize uint32
|
||||||
|
SecurityTrailer uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
//sys QuerySecurityPackageInfo(pkgname *uint16, pkginfo **SecPkgInfo) (ret syscall.Errno) = secur32.QuerySecurityPackageInfoW
|
||||||
|
//sys FreeContextBuffer(buf *byte) (ret syscall.Errno) = secur32.FreeContextBuffer
|
||||||
|
|
||||||
|
const (
|
||||||
|
SECPKG_CRED_INBOUND = 1
|
||||||
|
SECPKG_CRED_OUTBOUND = 2
|
||||||
|
SECPKG_CRED_BOTH = (SECPKG_CRED_OUTBOUND | SECPKG_CRED_INBOUND)
|
||||||
|
|
||||||
|
SEC_WINNT_AUTH_IDENTITY_UNICODE = 0x2
|
||||||
|
)
|
||||||
|
|
||||||
|
type SEC_WINNT_AUTH_IDENTITY struct {
|
||||||
|
User *uint16
|
||||||
|
UserLength uint32
|
||||||
|
Domain *uint16
|
||||||
|
DomainLength uint32
|
||||||
|
Password *uint16
|
||||||
|
PasswordLength uint32
|
||||||
|
Flags uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
type LUID struct {
|
||||||
|
LowPart uint32
|
||||||
|
HighPart int32
|
||||||
|
}
|
||||||
|
|
||||||
|
type CredHandle struct {
|
||||||
|
Lower uintptr
|
||||||
|
Upper uintptr
|
||||||
|
}
|
||||||
|
|
||||||
|
//sys AcquireCredentialsHandle(principal *uint16, pkgname *uint16, creduse uint32, logonid *LUID, authdata *byte, getkeyfn uintptr, getkeyarg uintptr, handle *CredHandle, expiry *syscall.Filetime) (ret syscall.Errno) = secur32.AcquireCredentialsHandleW
|
||||||
|
//sys FreeCredentialsHandle(handle *CredHandle) (ret syscall.Errno) = secur32.FreeCredentialsHandle
|
||||||
|
|
||||||
|
const (
|
||||||
|
SECURITY_NATIVE_DREP = 16
|
||||||
|
|
||||||
|
SECBUFFER_DATA = 1
|
||||||
|
SECBUFFER_TOKEN = 2
|
||||||
|
SECBUFFER_PKG_PARAMS = 3
|
||||||
|
SECBUFFER_MISSING = 4
|
||||||
|
SECBUFFER_EXTRA = 5
|
||||||
|
SECBUFFER_STREAM_TRAILER = 6
|
||||||
|
SECBUFFER_STREAM_HEADER = 7
|
||||||
|
SECBUFFER_PADDING = 9
|
||||||
|
SECBUFFER_STREAM = 10
|
||||||
|
SECBUFFER_READONLY = 0x80000000
|
||||||
|
SECBUFFER_ATTRMASK = 0xf0000000
|
||||||
|
SECBUFFER_VERSION = 0
|
||||||
|
SECBUFFER_EMPTY = 0
|
||||||
|
|
||||||
|
ISC_REQ_DELEGATE = 1
|
||||||
|
ISC_REQ_MUTUAL_AUTH = 2
|
||||||
|
ISC_REQ_REPLAY_DETECT = 4
|
||||||
|
ISC_REQ_SEQUENCE_DETECT = 8
|
||||||
|
ISC_REQ_CONFIDENTIALITY = 16
|
||||||
|
ISC_REQ_USE_SESSION_KEY = 32
|
||||||
|
ISC_REQ_PROMPT_FOR_CREDS = 64
|
||||||
|
ISC_REQ_USE_SUPPLIED_CREDS = 128
|
||||||
|
ISC_REQ_ALLOCATE_MEMORY = 256
|
||||||
|
ISC_REQ_USE_DCE_STYLE = 512
|
||||||
|
ISC_REQ_DATAGRAM = 1024
|
||||||
|
ISC_REQ_CONNECTION = 2048
|
||||||
|
ISC_REQ_EXTENDED_ERROR = 16384
|
||||||
|
ISC_REQ_STREAM = 32768
|
||||||
|
ISC_REQ_INTEGRITY = 65536
|
||||||
|
ISC_REQ_MANUAL_CRED_VALIDATION = 524288
|
||||||
|
ISC_REQ_HTTP = 268435456
|
||||||
|
|
||||||
|
ASC_REQ_DELEGATE = 1
|
||||||
|
ASC_REQ_MUTUAL_AUTH = 2
|
||||||
|
ASC_REQ_REPLAY_DETECT = 4
|
||||||
|
ASC_REQ_SEQUENCE_DETECT = 8
|
||||||
|
ASC_REQ_CONFIDENTIALITY = 16
|
||||||
|
ASC_REQ_USE_SESSION_KEY = 32
|
||||||
|
ASC_REQ_ALLOCATE_MEMORY = 256
|
||||||
|
ASC_REQ_USE_DCE_STYLE = 512
|
||||||
|
ASC_REQ_DATAGRAM = 1024
|
||||||
|
ASC_REQ_CONNECTION = 2048
|
||||||
|
ASC_REQ_EXTENDED_ERROR = 32768
|
||||||
|
ASC_REQ_STREAM = 65536
|
||||||
|
ASC_REQ_INTEGRITY = 131072
|
||||||
|
)
|
||||||
|
|
||||||
|
type CtxtHandle struct {
|
||||||
|
Lower uintptr
|
||||||
|
Upper uintptr
|
||||||
|
}
|
||||||
|
|
||||||
|
type SecBuffer struct {
|
||||||
|
BufferSize uint32
|
||||||
|
BufferType uint32
|
||||||
|
Buffer *byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type SecBufferDesc struct {
|
||||||
|
Version uint32
|
||||||
|
BuffersCount uint32
|
||||||
|
Buffers *SecBuffer
|
||||||
|
}
|
||||||
|
|
||||||
|
//sys InitializeSecurityContext(credential *CredHandle, context *CtxtHandle, targname *uint16, contextreq uint32, reserved1 uint32, targdatarep uint32, input *SecBufferDesc, reserved2 uint32, newcontext *CtxtHandle, output *SecBufferDesc, contextattr *uint32, expiry *syscall.Filetime) (ret syscall.Errno) = secur32.InitializeSecurityContextW
|
||||||
|
//sys AcceptSecurityContext(credential *CredHandle, context *CtxtHandle, input *SecBufferDesc, contextreq uint32, targdatarep uint32, newcontext *CtxtHandle, output *SecBufferDesc, contextattr *uint32, expiry *syscall.Filetime) (ret syscall.Errno) = secur32.AcceptSecurityContext
|
||||||
|
//sys CompleteAuthToken(context *CtxtHandle, token *SecBufferDesc) (ret syscall.Errno) = secur32.CompleteAuthToken
|
||||||
|
//sys DeleteSecurityContext(context *CtxtHandle) (ret syscall.Errno) = secur32.DeleteSecurityContext
|
||||||
|
//sys ImpersonateSecurityContext(context *CtxtHandle) (ret syscall.Errno) = secur32.ImpersonateSecurityContext
|
||||||
|
//sys RevertSecurityContext(context *CtxtHandle) (ret syscall.Errno) = secur32.RevertSecurityContext
|
||||||
|
//sys QueryContextAttributes(context *CtxtHandle, attribute uint32, buf *byte) (ret syscall.Errno) = secur32.QueryContextAttributesW
|
||||||
|
//sys EncryptMessage(context *CtxtHandle, qop uint32, message *SecBufferDesc, messageseqno uint32) (ret syscall.Errno) = secur32.EncryptMessage
|
||||||
|
//sys DecryptMessage(context *CtxtHandle, message *SecBufferDesc, messageseqno uint32, qop *uint32) (ret syscall.Errno) = secur32.DecryptMessage
|
||||||
|
//sys ApplyControlToken(context *CtxtHandle, input *SecBufferDesc) (ret syscall.Errno) = secur32.ApplyControlToken
|
||||||
|
//sys MakeSignature(context *CtxtHandle, qop uint32, message *SecBufferDesc, messageseqno uint32) (ret syscall.Errno) = secur32.MakeSignature
|
||||||
|
//sys VerifySignature(context *CtxtHandle, message *SecBufferDesc, messageseqno uint32, qop *uint32) (ret syscall.Errno) = secur32.VerifySignature
|
152
vendor/github.com/alexbrainman/sspi/zsyscall_windows.go
generated
vendored
Normal file
152
vendor/github.com/alexbrainman/sspi/zsyscall_windows.go
generated
vendored
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
|
||||||
|
|
||||||
|
package sspi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ unsafe.Pointer
|
||||||
|
|
||||||
|
// Do the interface allocations only once for common
|
||||||
|
// Errno values.
|
||||||
|
const (
|
||||||
|
errnoERROR_IO_PENDING = 997
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
|
||||||
|
)
|
||||||
|
|
||||||
|
// errnoErr returns common boxed Errno values, to prevent
|
||||||
|
// allocations at runtime.
|
||||||
|
func errnoErr(e syscall.Errno) error {
|
||||||
|
switch e {
|
||||||
|
case 0:
|
||||||
|
return nil
|
||||||
|
case errnoERROR_IO_PENDING:
|
||||||
|
return errERROR_IO_PENDING
|
||||||
|
}
|
||||||
|
// TODO: add more here, after collecting data on the common
|
||||||
|
// error values see on Windows. (perhaps when running
|
||||||
|
// all.bat?)
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
modsecur32 = syscall.NewLazyDLL("secur32.dll")
|
||||||
|
|
||||||
|
procQuerySecurityPackageInfoW = modsecur32.NewProc("QuerySecurityPackageInfoW")
|
||||||
|
procFreeContextBuffer = modsecur32.NewProc("FreeContextBuffer")
|
||||||
|
procAcquireCredentialsHandleW = modsecur32.NewProc("AcquireCredentialsHandleW")
|
||||||
|
procFreeCredentialsHandle = modsecur32.NewProc("FreeCredentialsHandle")
|
||||||
|
procInitializeSecurityContextW = modsecur32.NewProc("InitializeSecurityContextW")
|
||||||
|
procAcceptSecurityContext = modsecur32.NewProc("AcceptSecurityContext")
|
||||||
|
procCompleteAuthToken = modsecur32.NewProc("CompleteAuthToken")
|
||||||
|
procDeleteSecurityContext = modsecur32.NewProc("DeleteSecurityContext")
|
||||||
|
procImpersonateSecurityContext = modsecur32.NewProc("ImpersonateSecurityContext")
|
||||||
|
procRevertSecurityContext = modsecur32.NewProc("RevertSecurityContext")
|
||||||
|
procQueryContextAttributesW = modsecur32.NewProc("QueryContextAttributesW")
|
||||||
|
procEncryptMessage = modsecur32.NewProc("EncryptMessage")
|
||||||
|
procDecryptMessage = modsecur32.NewProc("DecryptMessage")
|
||||||
|
procApplyControlToken = modsecur32.NewProc("ApplyControlToken")
|
||||||
|
procMakeSignature = modsecur32.NewProc("MakeSignature")
|
||||||
|
procVerifySignature = modsecur32.NewProc("VerifySignature")
|
||||||
|
)
|
||||||
|
|
||||||
|
func QuerySecurityPackageInfo(pkgname *uint16, pkginfo **SecPkgInfo) (ret syscall.Errno) {
|
||||||
|
r0, _, _ := syscall.Syscall(procQuerySecurityPackageInfoW.Addr(), 2, uintptr(unsafe.Pointer(pkgname)), uintptr(unsafe.Pointer(pkginfo)), 0)
|
||||||
|
ret = syscall.Errno(r0)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func FreeContextBuffer(buf *byte) (ret syscall.Errno) {
|
||||||
|
r0, _, _ := syscall.Syscall(procFreeContextBuffer.Addr(), 1, uintptr(unsafe.Pointer(buf)), 0, 0)
|
||||||
|
ret = syscall.Errno(r0)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func AcquireCredentialsHandle(principal *uint16, pkgname *uint16, creduse uint32, logonid *LUID, authdata *byte, getkeyfn uintptr, getkeyarg uintptr, handle *CredHandle, expiry *syscall.Filetime) (ret syscall.Errno) {
|
||||||
|
r0, _, _ := syscall.Syscall9(procAcquireCredentialsHandleW.Addr(), 9, uintptr(unsafe.Pointer(principal)), uintptr(unsafe.Pointer(pkgname)), uintptr(creduse), uintptr(unsafe.Pointer(logonid)), uintptr(unsafe.Pointer(authdata)), uintptr(getkeyfn), uintptr(getkeyarg), uintptr(unsafe.Pointer(handle)), uintptr(unsafe.Pointer(expiry)))
|
||||||
|
ret = syscall.Errno(r0)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func FreeCredentialsHandle(handle *CredHandle) (ret syscall.Errno) {
|
||||||
|
r0, _, _ := syscall.Syscall(procFreeCredentialsHandle.Addr(), 1, uintptr(unsafe.Pointer(handle)), 0, 0)
|
||||||
|
ret = syscall.Errno(r0)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func InitializeSecurityContext(credential *CredHandle, context *CtxtHandle, targname *uint16, contextreq uint32, reserved1 uint32, targdatarep uint32, input *SecBufferDesc, reserved2 uint32, newcontext *CtxtHandle, output *SecBufferDesc, contextattr *uint32, expiry *syscall.Filetime) (ret syscall.Errno) {
|
||||||
|
r0, _, _ := syscall.Syscall12(procInitializeSecurityContextW.Addr(), 12, uintptr(unsafe.Pointer(credential)), uintptr(unsafe.Pointer(context)), uintptr(unsafe.Pointer(targname)), uintptr(contextreq), uintptr(reserved1), uintptr(targdatarep), uintptr(unsafe.Pointer(input)), uintptr(reserved2), uintptr(unsafe.Pointer(newcontext)), uintptr(unsafe.Pointer(output)), uintptr(unsafe.Pointer(contextattr)), uintptr(unsafe.Pointer(expiry)))
|
||||||
|
ret = syscall.Errno(r0)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func AcceptSecurityContext(credential *CredHandle, context *CtxtHandle, input *SecBufferDesc, contextreq uint32, targdatarep uint32, newcontext *CtxtHandle, output *SecBufferDesc, contextattr *uint32, expiry *syscall.Filetime) (ret syscall.Errno) {
|
||||||
|
r0, _, _ := syscall.Syscall9(procAcceptSecurityContext.Addr(), 9, uintptr(unsafe.Pointer(credential)), uintptr(unsafe.Pointer(context)), uintptr(unsafe.Pointer(input)), uintptr(contextreq), uintptr(targdatarep), uintptr(unsafe.Pointer(newcontext)), uintptr(unsafe.Pointer(output)), uintptr(unsafe.Pointer(contextattr)), uintptr(unsafe.Pointer(expiry)))
|
||||||
|
ret = syscall.Errno(r0)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func CompleteAuthToken(context *CtxtHandle, token *SecBufferDesc) (ret syscall.Errno) {
|
||||||
|
r0, _, _ := syscall.Syscall(procCompleteAuthToken.Addr(), 2, uintptr(unsafe.Pointer(context)), uintptr(unsafe.Pointer(token)), 0)
|
||||||
|
ret = syscall.Errno(r0)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteSecurityContext(context *CtxtHandle) (ret syscall.Errno) {
|
||||||
|
r0, _, _ := syscall.Syscall(procDeleteSecurityContext.Addr(), 1, uintptr(unsafe.Pointer(context)), 0, 0)
|
||||||
|
ret = syscall.Errno(r0)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func ImpersonateSecurityContext(context *CtxtHandle) (ret syscall.Errno) {
|
||||||
|
r0, _, _ := syscall.Syscall(procImpersonateSecurityContext.Addr(), 1, uintptr(unsafe.Pointer(context)), 0, 0)
|
||||||
|
ret = syscall.Errno(r0)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func RevertSecurityContext(context *CtxtHandle) (ret syscall.Errno) {
|
||||||
|
r0, _, _ := syscall.Syscall(procRevertSecurityContext.Addr(), 1, uintptr(unsafe.Pointer(context)), 0, 0)
|
||||||
|
ret = syscall.Errno(r0)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func QueryContextAttributes(context *CtxtHandle, attribute uint32, buf *byte) (ret syscall.Errno) {
|
||||||
|
r0, _, _ := syscall.Syscall(procQueryContextAttributesW.Addr(), 3, uintptr(unsafe.Pointer(context)), uintptr(attribute), uintptr(unsafe.Pointer(buf)))
|
||||||
|
ret = syscall.Errno(r0)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func EncryptMessage(context *CtxtHandle, qop uint32, message *SecBufferDesc, messageseqno uint32) (ret syscall.Errno) {
|
||||||
|
r0, _, _ := syscall.Syscall6(procEncryptMessage.Addr(), 4, uintptr(unsafe.Pointer(context)), uintptr(qop), uintptr(unsafe.Pointer(message)), uintptr(messageseqno), 0, 0)
|
||||||
|
ret = syscall.Errno(r0)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func DecryptMessage(context *CtxtHandle, message *SecBufferDesc, messageseqno uint32, qop *uint32) (ret syscall.Errno) {
|
||||||
|
r0, _, _ := syscall.Syscall6(procDecryptMessage.Addr(), 4, uintptr(unsafe.Pointer(context)), uintptr(unsafe.Pointer(message)), uintptr(messageseqno), uintptr(unsafe.Pointer(qop)), 0, 0)
|
||||||
|
ret = syscall.Errno(r0)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func ApplyControlToken(context *CtxtHandle, input *SecBufferDesc) (ret syscall.Errno) {
|
||||||
|
r0, _, _ := syscall.Syscall(procApplyControlToken.Addr(), 2, uintptr(unsafe.Pointer(context)), uintptr(unsafe.Pointer(input)), 0)
|
||||||
|
ret = syscall.Errno(r0)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func MakeSignature(context *CtxtHandle, qop uint32, message *SecBufferDesc, messageseqno uint32) (ret syscall.Errno) {
|
||||||
|
r0, _, _ := syscall.Syscall6(procMakeSignature.Addr(), 4, uintptr(unsafe.Pointer(context)), uintptr(qop), uintptr(unsafe.Pointer(message)), uintptr(messageseqno), 0, 0)
|
||||||
|
ret = syscall.Errno(r0)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func VerifySignature(context *CtxtHandle, message *SecBufferDesc, messageseqno uint32, qop *uint32) (ret syscall.Errno) {
|
||||||
|
r0, _, _ := syscall.Syscall6(procVerifySignature.Addr(), 4, uintptr(unsafe.Pointer(context)), uintptr(unsafe.Pointer(message)), uintptr(messageseqno), uintptr(unsafe.Pointer(qop)), 0, 0)
|
||||||
|
ret = syscall.Errno(r0)
|
||||||
|
return
|
||||||
|
}
|
12
vendor/github.com/hashicorp/go-uuid/.travis.yml
generated
vendored
Normal file
12
vendor/github.com/hashicorp/go-uuid/.travis.yml
generated
vendored
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
language: go
|
||||||
|
|
||||||
|
sudo: false
|
||||||
|
|
||||||
|
go:
|
||||||
|
- 1.4
|
||||||
|
- 1.5
|
||||||
|
- 1.6
|
||||||
|
- tip
|
||||||
|
|
||||||
|
script:
|
||||||
|
- go test -bench . -benchmem -v ./...
|
363
vendor/github.com/hashicorp/go-uuid/LICENSE
generated
vendored
Normal file
363
vendor/github.com/hashicorp/go-uuid/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,363 @@
|
||||||
|
Mozilla Public License, version 2.0
|
||||||
|
|
||||||
|
1. Definitions
|
||||||
|
|
||||||
|
1.1. "Contributor"
|
||||||
|
|
||||||
|
means each individual or legal entity that creates, contributes to the
|
||||||
|
creation of, or owns Covered Software.
|
||||||
|
|
||||||
|
1.2. "Contributor Version"
|
||||||
|
|
||||||
|
means the combination of the Contributions of others (if any) used by a
|
||||||
|
Contributor and that particular Contributor's Contribution.
|
||||||
|
|
||||||
|
1.3. "Contribution"
|
||||||
|
|
||||||
|
means Covered Software of a particular Contributor.
|
||||||
|
|
||||||
|
1.4. "Covered Software"
|
||||||
|
|
||||||
|
means Source Code Form to which the initial Contributor has attached the
|
||||||
|
notice in Exhibit A, the Executable Form of such Source Code Form, and
|
||||||
|
Modifications of such Source Code Form, in each case including portions
|
||||||
|
thereof.
|
||||||
|
|
||||||
|
1.5. "Incompatible With Secondary Licenses"
|
||||||
|
means
|
||||||
|
|
||||||
|
a. that the initial Contributor has attached the notice described in
|
||||||
|
Exhibit B to the Covered Software; or
|
||||||
|
|
||||||
|
b. that the Covered Software was made available under the terms of
|
||||||
|
version 1.1 or earlier of the License, but not also under the terms of
|
||||||
|
a Secondary License.
|
||||||
|
|
||||||
|
1.6. "Executable Form"
|
||||||
|
|
||||||
|
means any form of the work other than Source Code Form.
|
||||||
|
|
||||||
|
1.7. "Larger Work"
|
||||||
|
|
||||||
|
means a work that combines Covered Software with other material, in a
|
||||||
|
separate file or files, that is not Covered Software.
|
||||||
|
|
||||||
|
1.8. "License"
|
||||||
|
|
||||||
|
means this document.
|
||||||
|
|
||||||
|
1.9. "Licensable"
|
||||||
|
|
||||||
|
means having the right to grant, to the maximum extent possible, whether
|
||||||
|
at the time of the initial grant or subsequently, any and all of the
|
||||||
|
rights conveyed by this License.
|
||||||
|
|
||||||
|
1.10. "Modifications"
|
||||||
|
|
||||||
|
means any of the following:
|
||||||
|
|
||||||
|
a. any file in Source Code Form that results from an addition to,
|
||||||
|
deletion from, or modification of the contents of Covered Software; or
|
||||||
|
|
||||||
|
b. any new file in Source Code Form that contains any Covered Software.
|
||||||
|
|
||||||
|
1.11. "Patent Claims" of a Contributor
|
||||||
|
|
||||||
|
means any patent claim(s), including without limitation, method,
|
||||||
|
process, and apparatus claims, in any patent Licensable by such
|
||||||
|
Contributor that would be infringed, but for the grant of the License,
|
||||||
|
by the making, using, selling, offering for sale, having made, import,
|
||||||
|
or transfer of either its Contributions or its Contributor Version.
|
||||||
|
|
||||||
|
1.12. "Secondary License"
|
||||||
|
|
||||||
|
means either the GNU General Public License, Version 2.0, the GNU Lesser
|
||||||
|
General Public License, Version 2.1, the GNU Affero General Public
|
||||||
|
License, Version 3.0, or any later versions of those licenses.
|
||||||
|
|
||||||
|
1.13. "Source Code Form"
|
||||||
|
|
||||||
|
means the form of the work preferred for making modifications.
|
||||||
|
|
||||||
|
1.14. "You" (or "Your")
|
||||||
|
|
||||||
|
means an individual or a legal entity exercising rights under this
|
||||||
|
License. For legal entities, "You" includes any entity that controls, is
|
||||||
|
controlled by, or is under common control with You. For purposes of this
|
||||||
|
definition, "control" means (a) the power, direct or indirect, to cause
|
||||||
|
the direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (b) ownership of more than fifty percent (50%) of the
|
||||||
|
outstanding shares or beneficial ownership of such entity.
|
||||||
|
|
||||||
|
|
||||||
|
2. License Grants and Conditions
|
||||||
|
|
||||||
|
2.1. Grants
|
||||||
|
|
||||||
|
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||||
|
non-exclusive license:
|
||||||
|
|
||||||
|
a. under intellectual property rights (other than patent or trademark)
|
||||||
|
Licensable by such Contributor to use, reproduce, make available,
|
||||||
|
modify, display, perform, distribute, and otherwise exploit its
|
||||||
|
Contributions, either on an unmodified basis, with Modifications, or
|
||||||
|
as part of a Larger Work; and
|
||||||
|
|
||||||
|
b. under Patent Claims of such Contributor to make, use, sell, offer for
|
||||||
|
sale, have made, import, and otherwise transfer either its
|
||||||
|
Contributions or its Contributor Version.
|
||||||
|
|
||||||
|
2.2. Effective Date
|
||||||
|
|
||||||
|
The licenses granted in Section 2.1 with respect to any Contribution
|
||||||
|
become effective for each Contribution on the date the Contributor first
|
||||||
|
distributes such Contribution.
|
||||||
|
|
||||||
|
2.3. Limitations on Grant Scope
|
||||||
|
|
||||||
|
The licenses granted in this Section 2 are the only rights granted under
|
||||||
|
this License. No additional rights or licenses will be implied from the
|
||||||
|
distribution or licensing of Covered Software under this License.
|
||||||
|
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||||
|
Contributor:
|
||||||
|
|
||||||
|
a. for any code that a Contributor has removed from Covered Software; or
|
||||||
|
|
||||||
|
b. for infringements caused by: (i) Your and any other third party's
|
||||||
|
modifications of Covered Software, or (ii) the combination of its
|
||||||
|
Contributions with other software (except as part of its Contributor
|
||||||
|
Version); or
|
||||||
|
|
||||||
|
c. under Patent Claims infringed by Covered Software in the absence of
|
||||||
|
its Contributions.
|
||||||
|
|
||||||
|
This License does not grant any rights in the trademarks, service marks,
|
||||||
|
or logos of any Contributor (except as may be necessary to comply with
|
||||||
|
the notice requirements in Section 3.4).
|
||||||
|
|
||||||
|
2.4. Subsequent Licenses
|
||||||
|
|
||||||
|
No Contributor makes additional grants as a result of Your choice to
|
||||||
|
distribute the Covered Software under a subsequent version of this
|
||||||
|
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||||
|
permitted under the terms of Section 3.3).
|
||||||
|
|
||||||
|
2.5. Representation
|
||||||
|
|
||||||
|
Each Contributor represents that the Contributor believes its
|
||||||
|
Contributions are its original creation(s) or it has sufficient rights to
|
||||||
|
grant the rights to its Contributions conveyed by this License.
|
||||||
|
|
||||||
|
2.6. Fair Use
|
||||||
|
|
||||||
|
This License is not intended to limit any rights You have under
|
||||||
|
applicable copyright doctrines of fair use, fair dealing, or other
|
||||||
|
equivalents.
|
||||||
|
|
||||||
|
2.7. Conditions
|
||||||
|
|
||||||
|
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
|
||||||
|
Section 2.1.
|
||||||
|
|
||||||
|
|
||||||
|
3. Responsibilities
|
||||||
|
|
||||||
|
3.1. Distribution of Source Form
|
||||||
|
|
||||||
|
All distribution of Covered Software in Source Code Form, including any
|
||||||
|
Modifications that You create or to which You contribute, must be under
|
||||||
|
the terms of this License. You must inform recipients that the Source
|
||||||
|
Code Form of the Covered Software is governed by the terms of this
|
||||||
|
License, and how they can obtain a copy of this License. You may not
|
||||||
|
attempt to alter or restrict the recipients' rights in the Source Code
|
||||||
|
Form.
|
||||||
|
|
||||||
|
3.2. Distribution of Executable Form
|
||||||
|
|
||||||
|
If You distribute Covered Software in Executable Form then:
|
||||||
|
|
||||||
|
a. such Covered Software must also be made available in Source Code Form,
|
||||||
|
as described in Section 3.1, and You must inform recipients of the
|
||||||
|
Executable Form how they can obtain a copy of such Source Code Form by
|
||||||
|
reasonable means in a timely manner, at a charge no more than the cost
|
||||||
|
of distribution to the recipient; and
|
||||||
|
|
||||||
|
b. You may distribute such Executable Form under the terms of this
|
||||||
|
License, or sublicense it under different terms, provided that the
|
||||||
|
license for the Executable Form does not attempt to limit or alter the
|
||||||
|
recipients' rights in the Source Code Form under this License.
|
||||||
|
|
||||||
|
3.3. Distribution of a Larger Work
|
||||||
|
|
||||||
|
You may create and distribute a Larger Work under terms of Your choice,
|
||||||
|
provided that You also comply with the requirements of this License for
|
||||||
|
the Covered Software. If the Larger Work is a combination of Covered
|
||||||
|
Software with a work governed by one or more Secondary Licenses, and the
|
||||||
|
Covered Software is not Incompatible With Secondary Licenses, this
|
||||||
|
License permits You to additionally distribute such Covered Software
|
||||||
|
under the terms of such Secondary License(s), so that the recipient of
|
||||||
|
the Larger Work may, at their option, further distribute the Covered
|
||||||
|
Software under the terms of either this License or such Secondary
|
||||||
|
License(s).
|
||||||
|
|
||||||
|
3.4. Notices
|
||||||
|
|
||||||
|
You may not remove or alter the substance of any license notices
|
||||||
|
(including copyright notices, patent notices, disclaimers of warranty, or
|
||||||
|
limitations of liability) contained within the Source Code Form of the
|
||||||
|
Covered Software, except that You may alter any license notices to the
|
||||||
|
extent required to remedy known factual inaccuracies.
|
||||||
|
|
||||||
|
3.5. Application of Additional Terms
|
||||||
|
|
||||||
|
You may choose to offer, and to charge a fee for, warranty, support,
|
||||||
|
indemnity or liability obligations to one or more recipients of Covered
|
||||||
|
Software. However, You may do so only on Your own behalf, and not on
|
||||||
|
behalf of any Contributor. You must make it absolutely clear that any
|
||||||
|
such warranty, support, indemnity, or liability obligation is offered by
|
||||||
|
You alone, and You hereby agree to indemnify every Contributor for any
|
||||||
|
liability incurred by such Contributor as a result of warranty, support,
|
||||||
|
indemnity or liability terms You offer. You may include additional
|
||||||
|
disclaimers of warranty and limitations of liability specific to any
|
||||||
|
jurisdiction.
|
||||||
|
|
||||||
|
4. Inability to Comply Due to Statute or Regulation
|
||||||
|
|
||||||
|
If it is impossible for You to comply with any of the terms of this License
|
||||||
|
with respect to some or all of the Covered Software due to statute,
|
||||||
|
judicial order, or regulation then You must: (a) comply with the terms of
|
||||||
|
this License to the maximum extent possible; and (b) describe the
|
||||||
|
limitations and the code they affect. Such description must be placed in a
|
||||||
|
text file included with all distributions of the Covered Software under
|
||||||
|
this License. Except to the extent prohibited by statute or regulation,
|
||||||
|
such description must be sufficiently detailed for a recipient of ordinary
|
||||||
|
skill to be able to understand it.
|
||||||
|
|
||||||
|
5. Termination
|
||||||
|
|
||||||
|
5.1. The rights granted under this License will terminate automatically if You
|
||||||
|
fail to comply with any of its terms. However, if You become compliant,
|
||||||
|
then the rights granted under this License from a particular Contributor
|
||||||
|
are reinstated (a) provisionally, unless and until such Contributor
|
||||||
|
explicitly and finally terminates Your grants, and (b) on an ongoing
|
||||||
|
basis, if such Contributor fails to notify You of the non-compliance by
|
||||||
|
some reasonable means prior to 60 days after You have come back into
|
||||||
|
compliance. Moreover, Your grants from a particular Contributor are
|
||||||
|
reinstated on an ongoing basis if such Contributor notifies You of the
|
||||||
|
non-compliance by some reasonable means, this is the first time You have
|
||||||
|
received notice of non-compliance with this License from such
|
||||||
|
Contributor, and You become compliant prior to 30 days after Your receipt
|
||||||
|
of the notice.
|
||||||
|
|
||||||
|
5.2. If You initiate litigation against any entity by asserting a patent
|
||||||
|
infringement claim (excluding declaratory judgment actions,
|
||||||
|
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||||
|
directly or indirectly infringes any patent, then the rights granted to
|
||||||
|
You by any and all Contributors for the Covered Software under Section
|
||||||
|
2.1 of this License shall terminate.
|
||||||
|
|
||||||
|
5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
|
||||||
|
license agreements (excluding distributors and resellers) which have been
|
||||||
|
validly granted by You or Your distributors under this License prior to
|
||||||
|
termination shall survive termination.
|
||||||
|
|
||||||
|
6. Disclaimer of Warranty
|
||||||
|
|
||||||
|
Covered Software is provided under this License on an "as is" basis,
|
||||||
|
without warranty of any kind, either expressed, implied, or statutory,
|
||||||
|
including, without limitation, warranties that the Covered Software is free
|
||||||
|
of defects, merchantable, fit for a particular purpose or non-infringing.
|
||||||
|
The entire risk as to the quality and performance of the Covered Software
|
||||||
|
is with You. Should any Covered Software prove defective in any respect,
|
||||||
|
You (not any Contributor) assume the cost of any necessary servicing,
|
||||||
|
repair, or correction. This disclaimer of warranty constitutes an essential
|
||||||
|
part of this License. No use of any Covered Software is authorized under
|
||||||
|
this License except under this disclaimer.
|
||||||
|
|
||||||
|
7. Limitation of Liability
|
||||||
|
|
||||||
|
Under no circumstances and under no legal theory, whether tort (including
|
||||||
|
negligence), contract, or otherwise, shall any Contributor, or anyone who
|
||||||
|
distributes Covered Software as permitted above, be liable to You for any
|
||||||
|
direct, indirect, special, incidental, or consequential damages of any
|
||||||
|
character including, without limitation, damages for lost profits, loss of
|
||||||
|
goodwill, work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses, even if such party shall have been
|
||||||
|
informed of the possibility of such damages. This limitation of liability
|
||||||
|
shall not apply to liability for death or personal injury resulting from
|
||||||
|
such party's negligence to the extent applicable law prohibits such
|
||||||
|
limitation. Some jurisdictions do not allow the exclusion or limitation of
|
||||||
|
incidental or consequential damages, so this exclusion and limitation may
|
||||||
|
not apply to You.
|
||||||
|
|
||||||
|
8. Litigation
|
||||||
|
|
||||||
|
Any litigation relating to this License may be brought only in the courts
|
||||||
|
of a jurisdiction where the defendant maintains its principal place of
|
||||||
|
business and such litigation shall be governed by laws of that
|
||||||
|
jurisdiction, without reference to its conflict-of-law provisions. Nothing
|
||||||
|
in this Section shall prevent a party's ability to bring cross-claims or
|
||||||
|
counter-claims.
|
||||||
|
|
||||||
|
9. Miscellaneous
|
||||||
|
|
||||||
|
This License represents the complete agreement concerning the subject
|
||||||
|
matter hereof. If any provision of this License is held to be
|
||||||
|
unenforceable, such provision shall be reformed only to the extent
|
||||||
|
necessary to make it enforceable. Any law or regulation which provides that
|
||||||
|
the language of a contract shall be construed against the drafter shall not
|
||||||
|
be used to construe this License against a Contributor.
|
||||||
|
|
||||||
|
|
||||||
|
10. Versions of the License
|
||||||
|
|
||||||
|
10.1. New Versions
|
||||||
|
|
||||||
|
Mozilla Foundation is the license steward. Except as provided in Section
|
||||||
|
10.3, no one other than the license steward has the right to modify or
|
||||||
|
publish new versions of this License. Each version will be given a
|
||||||
|
distinguishing version number.
|
||||||
|
|
||||||
|
10.2. Effect of New Versions
|
||||||
|
|
||||||
|
You may distribute the Covered Software under the terms of the version
|
||||||
|
of the License under which You originally received the Covered Software,
|
||||||
|
or under the terms of any subsequent version published by the license
|
||||||
|
steward.
|
||||||
|
|
||||||
|
10.3. Modified Versions
|
||||||
|
|
||||||
|
If you create software not governed by this License, and you want to
|
||||||
|
create a new license for such software, you may create and use a
|
||||||
|
modified version of this License if you rename the license and remove
|
||||||
|
any references to the name of the license steward (except to note that
|
||||||
|
such modified license differs from this License).
|
||||||
|
|
||||||
|
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||||
|
Licenses If You choose to distribute Source Code Form that is
|
||||||
|
Incompatible With Secondary Licenses under the terms of this version of
|
||||||
|
the License, the notice described in Exhibit B of this License must be
|
||||||
|
attached.
|
||||||
|
|
||||||
|
Exhibit A - Source Code Form License Notice
|
||||||
|
|
||||||
|
This Source Code Form is subject to the
|
||||||
|
terms of the Mozilla Public License, v.
|
||||||
|
2.0. If a copy of the MPL was not
|
||||||
|
distributed with this file, You can
|
||||||
|
obtain one at
|
||||||
|
http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
If it is not possible or desirable to put the notice in a particular file,
|
||||||
|
then You may include the notice in a location (such as a LICENSE file in a
|
||||||
|
relevant directory) where a recipient would be likely to look for such a
|
||||||
|
notice.
|
||||||
|
|
||||||
|
You may add additional accurate notices of copyright ownership.
|
||||||
|
|
||||||
|
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||||
|
|
||||||
|
This Source Code Form is "Incompatible
|
||||||
|
With Secondary Licenses", as defined by
|
||||||
|
the Mozilla Public License, v. 2.0.
|
||||||
|
|
8
vendor/github.com/hashicorp/go-uuid/README.md
generated
vendored
Normal file
8
vendor/github.com/hashicorp/go-uuid/README.md
generated
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
# uuid [![Build Status](https://travis-ci.org/hashicorp/go-uuid.svg?branch=master)](https://travis-ci.org/hashicorp/go-uuid)
|
||||||
|
|
||||||
|
Generates UUID-format strings using high quality, _purely random_ bytes. It is **not** intended to be RFC compliant, merely to use a well-understood string representation of a 128-bit value. It can also parse UUID-format strings into their component bytes.
|
||||||
|
|
||||||
|
Documentation
|
||||||
|
=============
|
||||||
|
|
||||||
|
The full documentation is available on [Godoc](http://godoc.org/github.com/hashicorp/go-uuid).
|
1
vendor/github.com/hashicorp/go-uuid/go.mod
generated
vendored
Normal file
1
vendor/github.com/hashicorp/go-uuid/go.mod
generated
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
module github.com/hashicorp/go-uuid
|
83
vendor/github.com/hashicorp/go-uuid/uuid.go
generated
vendored
Normal file
83
vendor/github.com/hashicorp/go-uuid/uuid.go
generated
vendored
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
package uuid
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GenerateRandomBytes is used to generate random bytes of given size.
|
||||||
|
func GenerateRandomBytes(size int) ([]byte, error) {
|
||||||
|
return GenerateRandomBytesWithReader(size, rand.Reader)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerateRandomBytesWithReader is used to generate random bytes of given size read from a given reader.
|
||||||
|
func GenerateRandomBytesWithReader(size int, reader io.Reader) ([]byte, error) {
|
||||||
|
if reader == nil {
|
||||||
|
return nil, fmt.Errorf("provided reader is nil")
|
||||||
|
}
|
||||||
|
buf := make([]byte, size)
|
||||||
|
if _, err := io.ReadFull(reader, buf); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to read random bytes: %v", err)
|
||||||
|
}
|
||||||
|
return buf, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const uuidLen = 16
|
||||||
|
|
||||||
|
// GenerateUUID is used to generate a random UUID
|
||||||
|
func GenerateUUID() (string, error) {
|
||||||
|
return GenerateUUIDWithReader(rand.Reader)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerateUUIDWithReader is used to generate a random UUID with a given Reader
|
||||||
|
func GenerateUUIDWithReader(reader io.Reader) (string, error) {
|
||||||
|
if reader == nil {
|
||||||
|
return "", fmt.Errorf("provided reader is nil")
|
||||||
|
}
|
||||||
|
buf, err := GenerateRandomBytesWithReader(uuidLen, reader)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return FormatUUID(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
func FormatUUID(buf []byte) (string, error) {
|
||||||
|
if buflen := len(buf); buflen != uuidLen {
|
||||||
|
return "", fmt.Errorf("wrong length byte slice (%d)", buflen)
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("%x-%x-%x-%x-%x",
|
||||||
|
buf[0:4],
|
||||||
|
buf[4:6],
|
||||||
|
buf[6:8],
|
||||||
|
buf[8:10],
|
||||||
|
buf[10:16]), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseUUID(uuid string) ([]byte, error) {
|
||||||
|
if len(uuid) != 2 * uuidLen + 4 {
|
||||||
|
return nil, fmt.Errorf("uuid string is wrong length")
|
||||||
|
}
|
||||||
|
|
||||||
|
if uuid[8] != '-' ||
|
||||||
|
uuid[13] != '-' ||
|
||||||
|
uuid[18] != '-' ||
|
||||||
|
uuid[23] != '-' {
|
||||||
|
return nil, fmt.Errorf("uuid is improperly formatted")
|
||||||
|
}
|
||||||
|
|
||||||
|
hexStr := uuid[0:8] + uuid[9:13] + uuid[14:18] + uuid[19:23] + uuid[24:36]
|
||||||
|
|
||||||
|
ret, err := hex.DecodeString(hexStr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(ret) != uuidLen {
|
||||||
|
return nil, fmt.Errorf("decoded hex is the wrong length")
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret, nil
|
||||||
|
}
|
201
vendor/github.com/jcmturner/aescts/v2/LICENSE
generated
vendored
Normal file
201
vendor/github.com/jcmturner/aescts/v2/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright {yyyy} {name of copyright owner}
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
186
vendor/github.com/jcmturner/aescts/v2/aescts.go
generated
vendored
Normal file
186
vendor/github.com/jcmturner/aescts/v2/aescts.go
generated
vendored
Normal file
|
@ -0,0 +1,186 @@
|
||||||
|
// Package aescts provides AES CBC CipherText Stealing encryption and decryption methods
|
||||||
|
package aescts
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/aes"
|
||||||
|
"crypto/cipher"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Encrypt the message with the key and the initial vector.
|
||||||
|
// Returns: next iv, ciphertext bytes, error
|
||||||
|
func Encrypt(key, iv, plaintext []byte) ([]byte, []byte, error) {
|
||||||
|
l := len(plaintext)
|
||||||
|
|
||||||
|
block, err := aes.NewCipher(key)
|
||||||
|
if err != nil {
|
||||||
|
return []byte{}, []byte{}, fmt.Errorf("error creating cipher: %v", err)
|
||||||
|
}
|
||||||
|
mode := cipher.NewCBCEncrypter(block, iv)
|
||||||
|
|
||||||
|
m := make([]byte, len(plaintext))
|
||||||
|
copy(m, plaintext)
|
||||||
|
|
||||||
|
/*For consistency, ciphertext stealing is always used for the last two
|
||||||
|
blocks of the data to be encrypted, as in [RC5]. If the data length
|
||||||
|
is a multiple of the block size, this is equivalent to plain CBC mode
|
||||||
|
with the last two ciphertext blocks swapped.*/
|
||||||
|
/*The initial vector carried out from one encryption for use in a
|
||||||
|
subsequent encryption is the next-to-last block of the encryption
|
||||||
|
output; this is the encrypted form of the last plaintext block.*/
|
||||||
|
if l <= aes.BlockSize {
|
||||||
|
m, _ = zeroPad(m, aes.BlockSize)
|
||||||
|
mode.CryptBlocks(m, m)
|
||||||
|
return m, m, nil
|
||||||
|
}
|
||||||
|
if l%aes.BlockSize == 0 {
|
||||||
|
mode.CryptBlocks(m, m)
|
||||||
|
iv = m[len(m)-aes.BlockSize:]
|
||||||
|
rb, _ := swapLastTwoBlocks(m, aes.BlockSize)
|
||||||
|
return iv, rb, nil
|
||||||
|
}
|
||||||
|
m, _ = zeroPad(m, aes.BlockSize)
|
||||||
|
rb, pb, lb, err := tailBlocks(m, aes.BlockSize)
|
||||||
|
if err != nil {
|
||||||
|
return []byte{}, []byte{}, fmt.Errorf("error tailing blocks: %v", err)
|
||||||
|
}
|
||||||
|
var ct []byte
|
||||||
|
if rb != nil {
|
||||||
|
// Encrpt all but the lats 2 blocks and update the rolling iv
|
||||||
|
mode.CryptBlocks(rb, rb)
|
||||||
|
iv = rb[len(rb)-aes.BlockSize:]
|
||||||
|
mode = cipher.NewCBCEncrypter(block, iv)
|
||||||
|
ct = append(ct, rb...)
|
||||||
|
}
|
||||||
|
mode.CryptBlocks(pb, pb)
|
||||||
|
mode = cipher.NewCBCEncrypter(block, pb)
|
||||||
|
mode.CryptBlocks(lb, lb)
|
||||||
|
// Cipher Text Stealing (CTS) - Ref: https://en.wikipedia.org/wiki/Ciphertext_stealing#CBC_ciphertext_stealing
|
||||||
|
// Swap the last two cipher blocks
|
||||||
|
// Truncate the ciphertext to the length of the original plaintext
|
||||||
|
ct = append(ct, lb...)
|
||||||
|
ct = append(ct, pb...)
|
||||||
|
return lb, ct[:l], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decrypt the ciphertext with the key and the initial vector.
|
||||||
|
func Decrypt(key, iv, ciphertext []byte) ([]byte, error) {
|
||||||
|
// Copy the cipher text as golang slices even when passed by value to this method can result in the backing arrays of the calling code value being updated.
|
||||||
|
ct := make([]byte, len(ciphertext))
|
||||||
|
copy(ct, ciphertext)
|
||||||
|
if len(ct) < aes.BlockSize {
|
||||||
|
return []byte{}, fmt.Errorf("ciphertext is not large enough. It is less that one block size. Blocksize:%v; Ciphertext:%v", aes.BlockSize, len(ct))
|
||||||
|
}
|
||||||
|
// Configure the CBC
|
||||||
|
block, err := aes.NewCipher(key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error creating cipher: %v", err)
|
||||||
|
}
|
||||||
|
var mode cipher.BlockMode
|
||||||
|
|
||||||
|
//If ciphertext is multiple of blocksize we just need to swap back the last two blocks and then do CBC
|
||||||
|
//If the ciphertext is just one block we can't swap so we just decrypt
|
||||||
|
if len(ct)%aes.BlockSize == 0 {
|
||||||
|
if len(ct) > aes.BlockSize {
|
||||||
|
ct, _ = swapLastTwoBlocks(ct, aes.BlockSize)
|
||||||
|
}
|
||||||
|
mode = cipher.NewCBCDecrypter(block, iv)
|
||||||
|
message := make([]byte, len(ct))
|
||||||
|
mode.CryptBlocks(message, ct)
|
||||||
|
return message[:len(ct)], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cipher Text Stealing (CTS) using CBC interface. Ref: https://en.wikipedia.org/wiki/Ciphertext_stealing#CBC_ciphertext_stealing
|
||||||
|
// Get ciphertext of the 2nd to last (penultimate) block (cpb), the last block (clb) and the rest (crb)
|
||||||
|
crb, cpb, clb, _ := tailBlocks(ct, aes.BlockSize)
|
||||||
|
v := make([]byte, len(iv), len(iv))
|
||||||
|
copy(v, iv)
|
||||||
|
var message []byte
|
||||||
|
if crb != nil {
|
||||||
|
//If there is more than just the last and the penultimate block we decrypt it and the last bloc of this becomes the iv for later
|
||||||
|
rb := make([]byte, len(crb))
|
||||||
|
mode = cipher.NewCBCDecrypter(block, v)
|
||||||
|
v = crb[len(crb)-aes.BlockSize:]
|
||||||
|
mode.CryptBlocks(rb, crb)
|
||||||
|
message = append(message, rb...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to modify the cipher text
|
||||||
|
// Decryt the 2nd to last (penultimate) block with a the original iv
|
||||||
|
pb := make([]byte, aes.BlockSize)
|
||||||
|
mode = cipher.NewCBCDecrypter(block, iv)
|
||||||
|
mode.CryptBlocks(pb, cpb)
|
||||||
|
// number of byte needed to pad
|
||||||
|
npb := aes.BlockSize - len(ct)%aes.BlockSize
|
||||||
|
//pad last block using the number of bytes needed from the tail of the plaintext 2nd to last (penultimate) block
|
||||||
|
clb = append(clb, pb[len(pb)-npb:]...)
|
||||||
|
|
||||||
|
// Now decrypt the last block in the penultimate position (iv will be from the crb, if the is no crb it's zeros)
|
||||||
|
// iv for the penultimate block decrypted in the last position becomes the modified last block
|
||||||
|
lb := make([]byte, aes.BlockSize)
|
||||||
|
mode = cipher.NewCBCDecrypter(block, v)
|
||||||
|
v = clb
|
||||||
|
mode.CryptBlocks(lb, clb)
|
||||||
|
message = append(message, lb...)
|
||||||
|
|
||||||
|
// Now decrypt the penultimate block in the last position (iv will be from the modified last block)
|
||||||
|
mode = cipher.NewCBCDecrypter(block, v)
|
||||||
|
mode.CryptBlocks(cpb, cpb)
|
||||||
|
message = append(message, cpb...)
|
||||||
|
|
||||||
|
// Truncate to the size of the original cipher text
|
||||||
|
return message[:len(ct)], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func tailBlocks(b []byte, c int) ([]byte, []byte, []byte, error) {
|
||||||
|
if len(b) <= c {
|
||||||
|
return []byte{}, []byte{}, []byte{}, errors.New("bytes slice is not larger than one block so cannot tail")
|
||||||
|
}
|
||||||
|
// Get size of last block
|
||||||
|
var lbs int
|
||||||
|
if l := len(b) % aes.BlockSize; l == 0 {
|
||||||
|
lbs = aes.BlockSize
|
||||||
|
} else {
|
||||||
|
lbs = l
|
||||||
|
}
|
||||||
|
// Get last block
|
||||||
|
lb := b[len(b)-lbs:]
|
||||||
|
// Get 2nd to last (penultimate) block
|
||||||
|
pb := b[len(b)-lbs-c : len(b)-lbs]
|
||||||
|
if len(b) > 2*c {
|
||||||
|
rb := b[:len(b)-lbs-c]
|
||||||
|
return rb, pb, lb, nil
|
||||||
|
}
|
||||||
|
return nil, pb, lb, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func swapLastTwoBlocks(b []byte, c int) ([]byte, error) {
|
||||||
|
rb, pb, lb, err := tailBlocks(b, c)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var out []byte
|
||||||
|
if rb != nil {
|
||||||
|
out = append(out, rb...)
|
||||||
|
}
|
||||||
|
out = append(out, lb...)
|
||||||
|
out = append(out, pb...)
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// zeroPad pads bytes with zeros to nearest multiple of message size m.
|
||||||
|
func zeroPad(b []byte, m int) ([]byte, error) {
|
||||||
|
if m <= 0 {
|
||||||
|
return nil, errors.New("invalid message block size when padding")
|
||||||
|
}
|
||||||
|
if b == nil || len(b) == 0 {
|
||||||
|
return nil, errors.New("data not valid to pad: Zero size")
|
||||||
|
}
|
||||||
|
if l := len(b) % m; l != 0 {
|
||||||
|
n := m - l
|
||||||
|
z := make([]byte, n)
|
||||||
|
b = append(b, z...)
|
||||||
|
}
|
||||||
|
return b, nil
|
||||||
|
}
|
5
vendor/github.com/jcmturner/aescts/v2/go.mod
generated
vendored
Normal file
5
vendor/github.com/jcmturner/aescts/v2/go.mod
generated
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
module github.com/jcmturner/aescts/v2
|
||||||
|
|
||||||
|
go 1.13
|
||||||
|
|
||||||
|
require github.com/stretchr/testify v1.4.0
|
10
vendor/github.com/jcmturner/aescts/v2/go.sum
generated
vendored
Normal file
10
vendor/github.com/jcmturner/aescts/v2/go.sum
generated
vendored
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||||
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
201
vendor/github.com/jcmturner/dnsutils/v2/LICENSE
generated
vendored
Normal file
201
vendor/github.com/jcmturner/dnsutils/v2/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
5
vendor/github.com/jcmturner/dnsutils/v2/go.mod
generated
vendored
Normal file
5
vendor/github.com/jcmturner/dnsutils/v2/go.mod
generated
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
module github.com/jcmturner/dnsutils/v2
|
||||||
|
|
||||||
|
go 1.13
|
||||||
|
|
||||||
|
require github.com/stretchr/testify v1.4.0
|
10
vendor/github.com/jcmturner/dnsutils/v2/go.sum
generated
vendored
Normal file
10
vendor/github.com/jcmturner/dnsutils/v2/go.sum
generated
vendored
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||||
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
95
vendor/github.com/jcmturner/dnsutils/v2/srv.go
generated
vendored
Normal file
95
vendor/github.com/jcmturner/dnsutils/v2/srv.go
generated
vendored
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
package dnsutils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/rand"
|
||||||
|
"net"
|
||||||
|
"sort"
|
||||||
|
)
|
||||||
|
|
||||||
|
// OrderedSRV returns a count of the results and a map keyed on the order they should be used.
|
||||||
|
// This based on the records' priority and randomised selection based on their relative weighting.
|
||||||
|
// The function's inputs are the same as those for net.LookupSRV
|
||||||
|
// To use in the correct order:
|
||||||
|
//
|
||||||
|
// count, orderedSRV, err := OrderedSRV(service, proto, name)
|
||||||
|
// i := 1
|
||||||
|
// for i <= count {
|
||||||
|
// srv := orderedSRV[i]
|
||||||
|
// // Do something such as dial this SRV. If fails move on the the next or break if it succeeds.
|
||||||
|
// i += 1
|
||||||
|
// }
|
||||||
|
func OrderedSRV(service, proto, name string) (int, map[int]*net.SRV, error) {
|
||||||
|
_, addrs, err := net.LookupSRV(service, proto, name)
|
||||||
|
if err != nil {
|
||||||
|
return 0, make(map[int]*net.SRV), err
|
||||||
|
}
|
||||||
|
index, osrv := orderSRV(addrs)
|
||||||
|
return index, osrv, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func orderSRV(addrs []*net.SRV) (int, map[int]*net.SRV) {
|
||||||
|
// Initialise the ordered map
|
||||||
|
var o int
|
||||||
|
osrv := make(map[int]*net.SRV)
|
||||||
|
|
||||||
|
prioMap := make(map[int][]*net.SRV, 0)
|
||||||
|
for _, srv := range addrs {
|
||||||
|
prioMap[int(srv.Priority)] = append(prioMap[int(srv.Priority)], srv)
|
||||||
|
}
|
||||||
|
|
||||||
|
priorities := make([]int, 0)
|
||||||
|
for p := range prioMap {
|
||||||
|
priorities = append(priorities, p)
|
||||||
|
}
|
||||||
|
|
||||||
|
var count int
|
||||||
|
sort.Ints(priorities)
|
||||||
|
for _, p := range priorities {
|
||||||
|
tos := weightedOrder(prioMap[p])
|
||||||
|
for i, s := range tos {
|
||||||
|
count += 1
|
||||||
|
osrv[o+i] = s
|
||||||
|
}
|
||||||
|
o += len(tos)
|
||||||
|
}
|
||||||
|
return count, osrv
|
||||||
|
}
|
||||||
|
|
||||||
|
func weightedOrder(srvs []*net.SRV) map[int]*net.SRV {
|
||||||
|
// Get the total weight
|
||||||
|
var tw int
|
||||||
|
for _, s := range srvs {
|
||||||
|
tw += int(s.Weight)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialise the ordered map
|
||||||
|
o := 1
|
||||||
|
osrv := make(map[int]*net.SRV)
|
||||||
|
|
||||||
|
// Whilst there are still entries to be ordered
|
||||||
|
l := len(srvs)
|
||||||
|
for l > 0 {
|
||||||
|
i := rand.Intn(l)
|
||||||
|
s := srvs[i]
|
||||||
|
var rw int
|
||||||
|
if tw > 0 {
|
||||||
|
// Greater the weight the more likely this will be zero or less
|
||||||
|
rw = rand.Intn(tw) - int(s.Weight)
|
||||||
|
}
|
||||||
|
if rw <= 0 {
|
||||||
|
// Put entry in position
|
||||||
|
osrv[o] = s
|
||||||
|
if len(srvs) > 1 {
|
||||||
|
// Remove the entry from the source slice by swapping with the last entry and truncating
|
||||||
|
srvs[len(srvs)-1], srvs[i] = srvs[i], srvs[len(srvs)-1]
|
||||||
|
srvs = srvs[:len(srvs)-1]
|
||||||
|
l = len(srvs)
|
||||||
|
} else {
|
||||||
|
l = 0
|
||||||
|
}
|
||||||
|
o += 1
|
||||||
|
tw = tw - int(s.Weight)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return osrv
|
||||||
|
}
|
27
vendor/github.com/jcmturner/gofork/LICENSE
generated
vendored
Normal file
27
vendor/github.com/jcmturner/gofork/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
Copyright (c) 2009 The Go Authors. 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 Google Inc. nor the names of its
|
||||||
|
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.
|
5
vendor/github.com/jcmturner/gofork/encoding/asn1/README.md
generated
vendored
Normal file
5
vendor/github.com/jcmturner/gofork/encoding/asn1/README.md
generated
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
This is a temporary repository that will be removed when the issues below are fixed in the core golang code.
|
||||||
|
|
||||||
|
## Issues
|
||||||
|
* [encoding/asn1: cannot marshal into a GeneralString](https://github.com/golang/go/issues/18832)
|
||||||
|
* [encoding/asn1: cannot marshal into slice of strings and pass stringtype parameter tags to members](https://github.com/golang/go/issues/18834)
|
1003
vendor/github.com/jcmturner/gofork/encoding/asn1/asn1.go
generated
vendored
Normal file
1003
vendor/github.com/jcmturner/gofork/encoding/asn1/asn1.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
173
vendor/github.com/jcmturner/gofork/encoding/asn1/common.go
generated
vendored
Normal file
173
vendor/github.com/jcmturner/gofork/encoding/asn1/common.go
generated
vendored
Normal file
|
@ -0,0 +1,173 @@
|
||||||
|
// Copyright 2009 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package asn1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ASN.1 objects have metadata preceding them:
|
||||||
|
// the tag: the type of the object
|
||||||
|
// a flag denoting if this object is compound or not
|
||||||
|
// the class type: the namespace of the tag
|
||||||
|
// the length of the object, in bytes
|
||||||
|
|
||||||
|
// Here are some standard tags and classes
|
||||||
|
|
||||||
|
// ASN.1 tags represent the type of the following object.
|
||||||
|
const (
|
||||||
|
TagBoolean = 1
|
||||||
|
TagInteger = 2
|
||||||
|
TagBitString = 3
|
||||||
|
TagOctetString = 4
|
||||||
|
TagOID = 6
|
||||||
|
TagEnum = 10
|
||||||
|
TagUTF8String = 12
|
||||||
|
TagSequence = 16
|
||||||
|
TagSet = 17
|
||||||
|
TagPrintableString = 19
|
||||||
|
TagT61String = 20
|
||||||
|
TagIA5String = 22
|
||||||
|
TagUTCTime = 23
|
||||||
|
TagGeneralizedTime = 24
|
||||||
|
TagGeneralString = 27
|
||||||
|
)
|
||||||
|
|
||||||
|
// ASN.1 class types represent the namespace of the tag.
|
||||||
|
const (
|
||||||
|
ClassUniversal = 0
|
||||||
|
ClassApplication = 1
|
||||||
|
ClassContextSpecific = 2
|
||||||
|
ClassPrivate = 3
|
||||||
|
)
|
||||||
|
|
||||||
|
type tagAndLength struct {
|
||||||
|
class, tag, length int
|
||||||
|
isCompound bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// ASN.1 has IMPLICIT and EXPLICIT tags, which can be translated as "instead
|
||||||
|
// of" and "in addition to". When not specified, every primitive type has a
|
||||||
|
// default tag in the UNIVERSAL class.
|
||||||
|
//
|
||||||
|
// For example: a BIT STRING is tagged [UNIVERSAL 3] by default (although ASN.1
|
||||||
|
// doesn't actually have a UNIVERSAL keyword). However, by saying [IMPLICIT
|
||||||
|
// CONTEXT-SPECIFIC 42], that means that the tag is replaced by another.
|
||||||
|
//
|
||||||
|
// On the other hand, if it said [EXPLICIT CONTEXT-SPECIFIC 10], then an
|
||||||
|
// /additional/ tag would wrap the default tag. This explicit tag will have the
|
||||||
|
// compound flag set.
|
||||||
|
//
|
||||||
|
// (This is used in order to remove ambiguity with optional elements.)
|
||||||
|
//
|
||||||
|
// You can layer EXPLICIT and IMPLICIT tags to an arbitrary depth, however we
|
||||||
|
// don't support that here. We support a single layer of EXPLICIT or IMPLICIT
|
||||||
|
// tagging with tag strings on the fields of a structure.
|
||||||
|
|
||||||
|
// fieldParameters is the parsed representation of tag string from a structure field.
|
||||||
|
type fieldParameters struct {
|
||||||
|
optional bool // true iff the field is OPTIONAL
|
||||||
|
explicit bool // true iff an EXPLICIT tag is in use.
|
||||||
|
application bool // true iff an APPLICATION tag is in use.
|
||||||
|
defaultValue *int64 // a default value for INTEGER typed fields (maybe nil).
|
||||||
|
tag *int // the EXPLICIT or IMPLICIT tag (maybe nil).
|
||||||
|
stringType int // the string tag to use when marshaling.
|
||||||
|
timeType int // the time tag to use when marshaling.
|
||||||
|
set bool // true iff this should be encoded as a SET
|
||||||
|
omitEmpty bool // true iff this should be omitted if empty when marshaling.
|
||||||
|
|
||||||
|
// Invariants:
|
||||||
|
// if explicit is set, tag is non-nil.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Given a tag string with the format specified in the package comment,
|
||||||
|
// parseFieldParameters will parse it into a fieldParameters structure,
|
||||||
|
// ignoring unknown parts of the string.
|
||||||
|
func parseFieldParameters(str string) (ret fieldParameters) {
|
||||||
|
for _, part := range strings.Split(str, ",") {
|
||||||
|
switch {
|
||||||
|
case part == "optional":
|
||||||
|
ret.optional = true
|
||||||
|
case part == "explicit":
|
||||||
|
ret.explicit = true
|
||||||
|
if ret.tag == nil {
|
||||||
|
ret.tag = new(int)
|
||||||
|
}
|
||||||
|
case part == "generalized":
|
||||||
|
ret.timeType = TagGeneralizedTime
|
||||||
|
case part == "utc":
|
||||||
|
ret.timeType = TagUTCTime
|
||||||
|
case part == "ia5":
|
||||||
|
ret.stringType = TagIA5String
|
||||||
|
// jtasn1 case below added
|
||||||
|
case part == "generalstring":
|
||||||
|
ret.stringType = TagGeneralString
|
||||||
|
case part == "printable":
|
||||||
|
ret.stringType = TagPrintableString
|
||||||
|
case part == "utf8":
|
||||||
|
ret.stringType = TagUTF8String
|
||||||
|
case strings.HasPrefix(part, "default:"):
|
||||||
|
i, err := strconv.ParseInt(part[8:], 10, 64)
|
||||||
|
if err == nil {
|
||||||
|
ret.defaultValue = new(int64)
|
||||||
|
*ret.defaultValue = i
|
||||||
|
}
|
||||||
|
case strings.HasPrefix(part, "tag:"):
|
||||||
|
i, err := strconv.Atoi(part[4:])
|
||||||
|
if err == nil {
|
||||||
|
ret.tag = new(int)
|
||||||
|
*ret.tag = i
|
||||||
|
}
|
||||||
|
case part == "set":
|
||||||
|
ret.set = true
|
||||||
|
case part == "application":
|
||||||
|
ret.application = true
|
||||||
|
if ret.tag == nil {
|
||||||
|
ret.tag = new(int)
|
||||||
|
}
|
||||||
|
case part == "omitempty":
|
||||||
|
ret.omitEmpty = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Given a reflected Go type, getUniversalType returns the default tag number
|
||||||
|
// and expected compound flag.
|
||||||
|
func getUniversalType(t reflect.Type) (tagNumber int, isCompound, ok bool) {
|
||||||
|
switch t {
|
||||||
|
case objectIdentifierType:
|
||||||
|
return TagOID, false, true
|
||||||
|
case bitStringType:
|
||||||
|
return TagBitString, false, true
|
||||||
|
case timeType:
|
||||||
|
return TagUTCTime, false, true
|
||||||
|
case enumeratedType:
|
||||||
|
return TagEnum, false, true
|
||||||
|
case bigIntType:
|
||||||
|
return TagInteger, false, true
|
||||||
|
}
|
||||||
|
switch t.Kind() {
|
||||||
|
case reflect.Bool:
|
||||||
|
return TagBoolean, false, true
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
return TagInteger, false, true
|
||||||
|
case reflect.Struct:
|
||||||
|
return TagSequence, true, true
|
||||||
|
case reflect.Slice:
|
||||||
|
if t.Elem().Kind() == reflect.Uint8 {
|
||||||
|
return TagOctetString, false, true
|
||||||
|
}
|
||||||
|
if strings.HasSuffix(t.Name(), "SET") {
|
||||||
|
return TagSet, true, true
|
||||||
|
}
|
||||||
|
return TagSequence, true, true
|
||||||
|
case reflect.String:
|
||||||
|
return TagPrintableString, false, true
|
||||||
|
}
|
||||||
|
return 0, false, false
|
||||||
|
}
|
659
vendor/github.com/jcmturner/gofork/encoding/asn1/marshal.go
generated
vendored
Normal file
659
vendor/github.com/jcmturner/gofork/encoding/asn1/marshal.go
generated
vendored
Normal file
|
@ -0,0 +1,659 @@
|
||||||
|
// Copyright 2009 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package asn1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"math/big"
|
||||||
|
"reflect"
|
||||||
|
"time"
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A forkableWriter is an in-memory buffer that can be
|
||||||
|
// 'forked' to create new forkableWriters that bracket the
|
||||||
|
// original. After
|
||||||
|
// pre, post := w.fork()
|
||||||
|
// the overall sequence of bytes represented is logically w+pre+post.
|
||||||
|
type forkableWriter struct {
|
||||||
|
*bytes.Buffer
|
||||||
|
pre, post *forkableWriter
|
||||||
|
}
|
||||||
|
|
||||||
|
func newForkableWriter() *forkableWriter {
|
||||||
|
return &forkableWriter{new(bytes.Buffer), nil, nil}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *forkableWriter) fork() (pre, post *forkableWriter) {
|
||||||
|
if f.pre != nil || f.post != nil {
|
||||||
|
panic("have already forked")
|
||||||
|
}
|
||||||
|
f.pre = newForkableWriter()
|
||||||
|
f.post = newForkableWriter()
|
||||||
|
return f.pre, f.post
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *forkableWriter) Len() (l int) {
|
||||||
|
l += f.Buffer.Len()
|
||||||
|
if f.pre != nil {
|
||||||
|
l += f.pre.Len()
|
||||||
|
}
|
||||||
|
if f.post != nil {
|
||||||
|
l += f.post.Len()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *forkableWriter) writeTo(out io.Writer) (n int, err error) {
|
||||||
|
n, err = out.Write(f.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var nn int
|
||||||
|
|
||||||
|
if f.pre != nil {
|
||||||
|
nn, err = f.pre.writeTo(out)
|
||||||
|
n += nn
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if f.post != nil {
|
||||||
|
nn, err = f.post.writeTo(out)
|
||||||
|
n += nn
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalBase128Int(out *forkableWriter, n int64) (err error) {
|
||||||
|
if n == 0 {
|
||||||
|
err = out.WriteByte(0)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
l := 0
|
||||||
|
for i := n; i > 0; i >>= 7 {
|
||||||
|
l++
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := l - 1; i >= 0; i-- {
|
||||||
|
o := byte(n >> uint(i*7))
|
||||||
|
o &= 0x7f
|
||||||
|
if i != 0 {
|
||||||
|
o |= 0x80
|
||||||
|
}
|
||||||
|
err = out.WriteByte(o)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalInt64(out *forkableWriter, i int64) (err error) {
|
||||||
|
n := int64Length(i)
|
||||||
|
|
||||||
|
for ; n > 0; n-- {
|
||||||
|
err = out.WriteByte(byte(i >> uint((n-1)*8)))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func int64Length(i int64) (numBytes int) {
|
||||||
|
numBytes = 1
|
||||||
|
|
||||||
|
for i > 127 {
|
||||||
|
numBytes++
|
||||||
|
i >>= 8
|
||||||
|
}
|
||||||
|
|
||||||
|
for i < -128 {
|
||||||
|
numBytes++
|
||||||
|
i >>= 8
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalBigInt(out *forkableWriter, n *big.Int) (err error) {
|
||||||
|
if n.Sign() < 0 {
|
||||||
|
// A negative number has to be converted to two's-complement
|
||||||
|
// form. So we'll subtract 1 and invert. If the
|
||||||
|
// most-significant-bit isn't set then we'll need to pad the
|
||||||
|
// beginning with 0xff in order to keep the number negative.
|
||||||
|
nMinus1 := new(big.Int).Neg(n)
|
||||||
|
nMinus1.Sub(nMinus1, bigOne)
|
||||||
|
bytes := nMinus1.Bytes()
|
||||||
|
for i := range bytes {
|
||||||
|
bytes[i] ^= 0xff
|
||||||
|
}
|
||||||
|
if len(bytes) == 0 || bytes[0]&0x80 == 0 {
|
||||||
|
err = out.WriteByte(0xff)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_, err = out.Write(bytes)
|
||||||
|
} else if n.Sign() == 0 {
|
||||||
|
// Zero is written as a single 0 zero rather than no bytes.
|
||||||
|
err = out.WriteByte(0x00)
|
||||||
|
} else {
|
||||||
|
bytes := n.Bytes()
|
||||||
|
if len(bytes) > 0 && bytes[0]&0x80 != 0 {
|
||||||
|
// We'll have to pad this with 0x00 in order to stop it
|
||||||
|
// looking like a negative number.
|
||||||
|
err = out.WriteByte(0)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_, err = out.Write(bytes)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalLength(out *forkableWriter, i int) (err error) {
|
||||||
|
n := lengthLength(i)
|
||||||
|
|
||||||
|
for ; n > 0; n-- {
|
||||||
|
err = out.WriteByte(byte(i >> uint((n-1)*8)))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func lengthLength(i int) (numBytes int) {
|
||||||
|
numBytes = 1
|
||||||
|
for i > 255 {
|
||||||
|
numBytes++
|
||||||
|
i >>= 8
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalTagAndLength(out *forkableWriter, t tagAndLength) (err error) {
|
||||||
|
b := uint8(t.class) << 6
|
||||||
|
if t.isCompound {
|
||||||
|
b |= 0x20
|
||||||
|
}
|
||||||
|
if t.tag >= 31 {
|
||||||
|
b |= 0x1f
|
||||||
|
err = out.WriteByte(b)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = marshalBase128Int(out, int64(t.tag))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
b |= uint8(t.tag)
|
||||||
|
err = out.WriteByte(b)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if t.length >= 128 {
|
||||||
|
l := lengthLength(t.length)
|
||||||
|
err = out.WriteByte(0x80 | byte(l))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = marshalLength(out, t.length)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err = out.WriteByte(byte(t.length))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalBitString(out *forkableWriter, b BitString) (err error) {
|
||||||
|
paddingBits := byte((8 - b.BitLength%8) % 8)
|
||||||
|
err = out.WriteByte(paddingBits)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, err = out.Write(b.Bytes)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalObjectIdentifier(out *forkableWriter, oid []int) (err error) {
|
||||||
|
if len(oid) < 2 || oid[0] > 2 || (oid[0] < 2 && oid[1] >= 40) {
|
||||||
|
return StructuralError{"invalid object identifier"}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = marshalBase128Int(out, int64(oid[0]*40+oid[1]))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for i := 2; i < len(oid); i++ {
|
||||||
|
err = marshalBase128Int(out, int64(oid[i]))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalPrintableString(out *forkableWriter, s string) (err error) {
|
||||||
|
b := []byte(s)
|
||||||
|
for _, c := range b {
|
||||||
|
if !isPrintable(c) {
|
||||||
|
return StructuralError{"PrintableString contains invalid character"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = out.Write(b)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalIA5String(out *forkableWriter, s string) (err error) {
|
||||||
|
b := []byte(s)
|
||||||
|
for _, c := range b {
|
||||||
|
if c > 127 {
|
||||||
|
return StructuralError{"IA5String contains invalid character"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = out.Write(b)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalUTF8String(out *forkableWriter, s string) (err error) {
|
||||||
|
_, err = out.Write([]byte(s))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalTwoDigits(out *forkableWriter, v int) (err error) {
|
||||||
|
err = out.WriteByte(byte('0' + (v/10)%10))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return out.WriteByte(byte('0' + v%10))
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalFourDigits(out *forkableWriter, v int) (err error) {
|
||||||
|
var bytes [4]byte
|
||||||
|
for i := range bytes {
|
||||||
|
bytes[3-i] = '0' + byte(v%10)
|
||||||
|
v /= 10
|
||||||
|
}
|
||||||
|
_, err = out.Write(bytes[:])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func outsideUTCRange(t time.Time) bool {
|
||||||
|
year := t.Year()
|
||||||
|
return year < 1950 || year >= 2050
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalUTCTime(out *forkableWriter, t time.Time) (err error) {
|
||||||
|
year := t.Year()
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case 1950 <= year && year < 2000:
|
||||||
|
err = marshalTwoDigits(out, year-1900)
|
||||||
|
case 2000 <= year && year < 2050:
|
||||||
|
err = marshalTwoDigits(out, year-2000)
|
||||||
|
default:
|
||||||
|
return StructuralError{"cannot represent time as UTCTime"}
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return marshalTimeCommon(out, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalGeneralizedTime(out *forkableWriter, t time.Time) (err error) {
|
||||||
|
year := t.Year()
|
||||||
|
if year < 0 || year > 9999 {
|
||||||
|
return StructuralError{"cannot represent time as GeneralizedTime"}
|
||||||
|
}
|
||||||
|
if err = marshalFourDigits(out, year); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return marshalTimeCommon(out, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalTimeCommon(out *forkableWriter, t time.Time) (err error) {
|
||||||
|
_, month, day := t.Date()
|
||||||
|
|
||||||
|
err = marshalTwoDigits(out, int(month))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = marshalTwoDigits(out, day)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
hour, min, sec := t.Clock()
|
||||||
|
|
||||||
|
err = marshalTwoDigits(out, hour)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = marshalTwoDigits(out, min)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = marshalTwoDigits(out, sec)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, offset := t.Zone()
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case offset/60 == 0:
|
||||||
|
err = out.WriteByte('Z')
|
||||||
|
return
|
||||||
|
case offset > 0:
|
||||||
|
err = out.WriteByte('+')
|
||||||
|
case offset < 0:
|
||||||
|
err = out.WriteByte('-')
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
offsetMinutes := offset / 60
|
||||||
|
if offsetMinutes < 0 {
|
||||||
|
offsetMinutes = -offsetMinutes
|
||||||
|
}
|
||||||
|
|
||||||
|
err = marshalTwoDigits(out, offsetMinutes/60)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = marshalTwoDigits(out, offsetMinutes%60)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func stripTagAndLength(in []byte) []byte {
|
||||||
|
_, offset, err := parseTagAndLength(in, 0)
|
||||||
|
if err != nil {
|
||||||
|
return in
|
||||||
|
}
|
||||||
|
return in[offset:]
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameters) (err error) {
|
||||||
|
switch value.Type() {
|
||||||
|
case flagType:
|
||||||
|
return nil
|
||||||
|
case timeType:
|
||||||
|
t := value.Interface().(time.Time)
|
||||||
|
if params.timeType == TagGeneralizedTime || outsideUTCRange(t) {
|
||||||
|
return marshalGeneralizedTime(out, t)
|
||||||
|
} else {
|
||||||
|
return marshalUTCTime(out, t)
|
||||||
|
}
|
||||||
|
case bitStringType:
|
||||||
|
return marshalBitString(out, value.Interface().(BitString))
|
||||||
|
case objectIdentifierType:
|
||||||
|
return marshalObjectIdentifier(out, value.Interface().(ObjectIdentifier))
|
||||||
|
case bigIntType:
|
||||||
|
return marshalBigInt(out, value.Interface().(*big.Int))
|
||||||
|
}
|
||||||
|
|
||||||
|
switch v := value; v.Kind() {
|
||||||
|
case reflect.Bool:
|
||||||
|
if v.Bool() {
|
||||||
|
return out.WriteByte(255)
|
||||||
|
} else {
|
||||||
|
return out.WriteByte(0)
|
||||||
|
}
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
return marshalInt64(out, v.Int())
|
||||||
|
case reflect.Struct:
|
||||||
|
t := v.Type()
|
||||||
|
|
||||||
|
startingField := 0
|
||||||
|
|
||||||
|
// If the first element of the structure is a non-empty
|
||||||
|
// RawContents, then we don't bother serializing the rest.
|
||||||
|
if t.NumField() > 0 && t.Field(0).Type == rawContentsType {
|
||||||
|
s := v.Field(0)
|
||||||
|
if s.Len() > 0 {
|
||||||
|
bytes := make([]byte, s.Len())
|
||||||
|
for i := 0; i < s.Len(); i++ {
|
||||||
|
bytes[i] = uint8(s.Index(i).Uint())
|
||||||
|
}
|
||||||
|
/* The RawContents will contain the tag and
|
||||||
|
* length fields but we'll also be writing
|
||||||
|
* those ourselves, so we strip them out of
|
||||||
|
* bytes */
|
||||||
|
_, err = out.Write(stripTagAndLength(bytes))
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
startingField = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := startingField; i < t.NumField(); i++ {
|
||||||
|
var pre *forkableWriter
|
||||||
|
pre, out = out.fork()
|
||||||
|
err = marshalField(pre, v.Field(i), parseFieldParameters(t.Field(i).Tag.Get("asn1")))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
case reflect.Slice:
|
||||||
|
sliceType := v.Type()
|
||||||
|
if sliceType.Elem().Kind() == reflect.Uint8 {
|
||||||
|
bytes := make([]byte, v.Len())
|
||||||
|
for i := 0; i < v.Len(); i++ {
|
||||||
|
bytes[i] = uint8(v.Index(i).Uint())
|
||||||
|
}
|
||||||
|
_, err = out.Write(bytes)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// jtasn1 Pass on the tags to the members but need to unset explicit switch and implicit value
|
||||||
|
//var fp fieldParameters
|
||||||
|
params.explicit = false
|
||||||
|
params.tag = nil
|
||||||
|
for i := 0; i < v.Len(); i++ {
|
||||||
|
var pre *forkableWriter
|
||||||
|
pre, out = out.fork()
|
||||||
|
err = marshalField(pre, v.Index(i), params)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
case reflect.String:
|
||||||
|
switch params.stringType {
|
||||||
|
case TagIA5String:
|
||||||
|
return marshalIA5String(out, v.String())
|
||||||
|
case TagPrintableString:
|
||||||
|
return marshalPrintableString(out, v.String())
|
||||||
|
default:
|
||||||
|
return marshalUTF8String(out, v.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return StructuralError{"unknown Go type"}
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters) (err error) {
|
||||||
|
if !v.IsValid() {
|
||||||
|
return fmt.Errorf("asn1: cannot marshal nil value")
|
||||||
|
}
|
||||||
|
// If the field is an interface{} then recurse into it.
|
||||||
|
if v.Kind() == reflect.Interface && v.Type().NumMethod() == 0 {
|
||||||
|
return marshalField(out, v.Elem(), params)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Kind() == reflect.Slice && v.Len() == 0 && params.omitEmpty {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if params.optional && params.defaultValue != nil && canHaveDefaultValue(v.Kind()) {
|
||||||
|
defaultValue := reflect.New(v.Type()).Elem()
|
||||||
|
defaultValue.SetInt(*params.defaultValue)
|
||||||
|
|
||||||
|
if reflect.DeepEqual(v.Interface(), defaultValue.Interface()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no default value is given then the zero value for the type is
|
||||||
|
// assumed to be the default value. This isn't obviously the correct
|
||||||
|
// behaviour, but it's what Go has traditionally done.
|
||||||
|
if params.optional && params.defaultValue == nil {
|
||||||
|
if reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Type() == rawValueType {
|
||||||
|
rv := v.Interface().(RawValue)
|
||||||
|
if len(rv.FullBytes) != 0 {
|
||||||
|
_, err = out.Write(rv.FullBytes)
|
||||||
|
} else {
|
||||||
|
err = marshalTagAndLength(out, tagAndLength{rv.Class, rv.Tag, len(rv.Bytes), rv.IsCompound})
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, err = out.Write(rv.Bytes)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
tag, isCompound, ok := getUniversalType(v.Type())
|
||||||
|
if !ok {
|
||||||
|
err = StructuralError{fmt.Sprintf("unknown Go type: %v", v.Type())}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
class := ClassUniversal
|
||||||
|
|
||||||
|
if params.timeType != 0 && tag != TagUTCTime {
|
||||||
|
return StructuralError{"explicit time type given to non-time member"}
|
||||||
|
}
|
||||||
|
|
||||||
|
// jtasn1 updated to allow slices of strings
|
||||||
|
if params.stringType != 0 && !(tag == TagPrintableString || (v.Kind() == reflect.Slice && tag == 16 && v.Type().Elem().Kind() == reflect.String)) {
|
||||||
|
return StructuralError{"explicit string type given to non-string member"}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch tag {
|
||||||
|
case TagPrintableString:
|
||||||
|
if params.stringType == 0 {
|
||||||
|
// This is a string without an explicit string type. We'll use
|
||||||
|
// a PrintableString if the character set in the string is
|
||||||
|
// sufficiently limited, otherwise we'll use a UTF8String.
|
||||||
|
for _, r := range v.String() {
|
||||||
|
if r >= utf8.RuneSelf || !isPrintable(byte(r)) {
|
||||||
|
if !utf8.ValidString(v.String()) {
|
||||||
|
return errors.New("asn1: string not valid UTF-8")
|
||||||
|
}
|
||||||
|
tag = TagUTF8String
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tag = params.stringType
|
||||||
|
}
|
||||||
|
case TagUTCTime:
|
||||||
|
if params.timeType == TagGeneralizedTime || outsideUTCRange(v.Interface().(time.Time)) {
|
||||||
|
tag = TagGeneralizedTime
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if params.set {
|
||||||
|
if tag != TagSequence {
|
||||||
|
return StructuralError{"non sequence tagged as set"}
|
||||||
|
}
|
||||||
|
tag = TagSet
|
||||||
|
}
|
||||||
|
|
||||||
|
tags, body := out.fork()
|
||||||
|
|
||||||
|
err = marshalBody(body, v, params)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
bodyLen := body.Len()
|
||||||
|
|
||||||
|
var explicitTag *forkableWriter
|
||||||
|
if params.explicit {
|
||||||
|
explicitTag, tags = tags.fork()
|
||||||
|
}
|
||||||
|
|
||||||
|
if !params.explicit && params.tag != nil {
|
||||||
|
// implicit tag.
|
||||||
|
tag = *params.tag
|
||||||
|
class = ClassContextSpecific
|
||||||
|
}
|
||||||
|
|
||||||
|
err = marshalTagAndLength(tags, tagAndLength{class, tag, bodyLen, isCompound})
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if params.explicit {
|
||||||
|
err = marshalTagAndLength(explicitTag, tagAndLength{
|
||||||
|
class: ClassContextSpecific,
|
||||||
|
tag: *params.tag,
|
||||||
|
length: bodyLen + tags.Len(),
|
||||||
|
isCompound: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marshal returns the ASN.1 encoding of val.
|
||||||
|
//
|
||||||
|
// In addition to the struct tags recognised by Unmarshal, the following can be
|
||||||
|
// used:
|
||||||
|
//
|
||||||
|
// ia5: causes strings to be marshaled as ASN.1, IA5 strings
|
||||||
|
// omitempty: causes empty slices to be skipped
|
||||||
|
// printable: causes strings to be marshaled as ASN.1, PrintableString strings.
|
||||||
|
// utf8: causes strings to be marshaled as ASN.1, UTF8 strings
|
||||||
|
func Marshal(val interface{}) ([]byte, error) {
|
||||||
|
var out bytes.Buffer
|
||||||
|
v := reflect.ValueOf(val)
|
||||||
|
f := newForkableWriter()
|
||||||
|
err := marshalField(f, v, fieldParameters{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
_, err = f.writeTo(&out)
|
||||||
|
return out.Bytes(), err
|
||||||
|
}
|
98
vendor/github.com/jcmturner/gofork/x/crypto/pbkdf2/pbkdf2.go
generated
vendored
Normal file
98
vendor/github.com/jcmturner/gofork/x/crypto/pbkdf2/pbkdf2.go
generated
vendored
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
// Copyright 2012 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package pbkdf2 implements the key derivation function PBKDF2 as defined in RFC
|
||||||
|
2898 / PKCS #5 v2.0.
|
||||||
|
|
||||||
|
A key derivation function is useful when encrypting data based on a password
|
||||||
|
or any other not-fully-random data. It uses a pseudorandom function to derive
|
||||||
|
a secure encryption key based on the password.
|
||||||
|
|
||||||
|
While v2.0 of the standard defines only one pseudorandom function to use,
|
||||||
|
HMAC-SHA1, the drafted v2.1 specification allows use of all five FIPS Approved
|
||||||
|
Hash Functions SHA-1, SHA-224, SHA-256, SHA-384 and SHA-512 for HMAC. To
|
||||||
|
choose, you can pass the `New` functions from the different SHA packages to
|
||||||
|
pbkdf2.Key.
|
||||||
|
*/
|
||||||
|
package pbkdf2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/hmac"
|
||||||
|
"hash"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Key derives a key from the password, salt and iteration count, returning a
|
||||||
|
// []byte of length keylen that can be used as cryptographic key. The key is
|
||||||
|
// derived based on the method described as PBKDF2 with the HMAC variant using
|
||||||
|
// the supplied hash function.
|
||||||
|
//
|
||||||
|
// For example, to use a HMAC-SHA-1 based PBKDF2 key derivation function, you
|
||||||
|
// can get a derived key for e.g. AES-256 (which needs a 32-byte key) by
|
||||||
|
// doing:
|
||||||
|
//
|
||||||
|
// dk := pbkdf2.Key([]byte("some password"), salt, 4096, 32, sha1.New)
|
||||||
|
//
|
||||||
|
// Remember to get a good random salt. At least 8 bytes is recommended by the
|
||||||
|
// RFC.
|
||||||
|
//
|
||||||
|
// Using a higher iteration count will increase the cost of an exhaustive
|
||||||
|
// search but will also make derivation proportionally slower.
|
||||||
|
func Key(password, salt []byte, iter, keyLen int, h func() hash.Hash) []byte {
|
||||||
|
return Key64(password, salt, int64(iter), int64(keyLen), h)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Key64 derives a key from the password, salt and iteration count, returning a
|
||||||
|
// []byte of length keylen that can be used as cryptographic key. Key64 uses
|
||||||
|
// int64 for the iteration count and key length to allow larger values.
|
||||||
|
// The key is derived based on the method described as PBKDF2 with the HMAC
|
||||||
|
// variant using the supplied hash function.
|
||||||
|
//
|
||||||
|
// For example, to use a HMAC-SHA-1 based PBKDF2 key derivation function, you
|
||||||
|
// can get a derived key for e.g. AES-256 (which needs a 32-byte key) by
|
||||||
|
// doing:
|
||||||
|
//
|
||||||
|
// dk := pbkdf2.Key([]byte("some password"), salt, 4096, 32, sha1.New)
|
||||||
|
//
|
||||||
|
// Remember to get a good random salt. At least 8 bytes is recommended by the
|
||||||
|
// RFC.
|
||||||
|
//
|
||||||
|
// Using a higher iteration count will increase the cost of an exhaustive
|
||||||
|
// search but will also make derivation proportionally slower.
|
||||||
|
func Key64(password, salt []byte, iter, keyLen int64, h func() hash.Hash) []byte {
|
||||||
|
prf := hmac.New(h, password)
|
||||||
|
hashLen := int64(prf.Size())
|
||||||
|
numBlocks := (keyLen + hashLen - 1) / hashLen
|
||||||
|
|
||||||
|
var buf [4]byte
|
||||||
|
dk := make([]byte, 0, numBlocks*hashLen)
|
||||||
|
U := make([]byte, hashLen)
|
||||||
|
for block := int64(1); block <= numBlocks; block++ {
|
||||||
|
// N.B.: || means concatenation, ^ means XOR
|
||||||
|
// for each block T_i = U_1 ^ U_2 ^ ... ^ U_iter
|
||||||
|
// U_1 = PRF(password, salt || uint(i))
|
||||||
|
prf.Reset()
|
||||||
|
prf.Write(salt)
|
||||||
|
buf[0] = byte(block >> 24)
|
||||||
|
buf[1] = byte(block >> 16)
|
||||||
|
buf[2] = byte(block >> 8)
|
||||||
|
buf[3] = byte(block)
|
||||||
|
prf.Write(buf[:4])
|
||||||
|
dk = prf.Sum(dk)
|
||||||
|
T := dk[int64(len(dk))-hashLen:]
|
||||||
|
copy(U, T)
|
||||||
|
|
||||||
|
// U_n = PRF(password, U_(n-1))
|
||||||
|
for n := int64(2); n <= iter; n++ {
|
||||||
|
prf.Reset()
|
||||||
|
prf.Write(U)
|
||||||
|
U = U[:0]
|
||||||
|
U = prf.Sum(U)
|
||||||
|
for x := range U {
|
||||||
|
T[x] ^= U[x]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dk[:keyLen]
|
||||||
|
}
|
201
vendor/github.com/jcmturner/goidentity/v6/LICENSE
generated
vendored
Normal file
201
vendor/github.com/jcmturner/goidentity/v6/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright {yyyy} {name of copyright owner}
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
7
vendor/github.com/jcmturner/goidentity/v6/README.md
generated
vendored
Normal file
7
vendor/github.com/jcmturner/goidentity/v6/README.md
generated
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# goidentity
|
||||||
|
[![GoDoc](https://godoc.org/github.com/jcmturner/goidentity/v6?status.svg)](https://godoc.org/github.com/jcmturner/goidentity/v6) [![Go Report Card](https://goreportcard.com/badge/github.com/jcmturner/goidentity/v6)](https://goreportcard.com/report/github.com/jcmturner/goidentity/v6)
|
||||||
|
|
||||||
|
Please import as below
|
||||||
|
```
|
||||||
|
import "github.com/jcmturner/goidentity/v6"
|
||||||
|
```
|
6
vendor/github.com/jcmturner/goidentity/v6/authenticator.go
generated
vendored
Normal file
6
vendor/github.com/jcmturner/goidentity/v6/authenticator.go
generated
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
package goidentity
|
||||||
|
|
||||||
|
type Authenticator interface {
|
||||||
|
Authenticate() (Identity, bool, error)
|
||||||
|
Mechanism() string // gives the name of the type of authentication mechanism
|
||||||
|
}
|
8
vendor/github.com/jcmturner/goidentity/v6/go.mod
generated
vendored
Normal file
8
vendor/github.com/jcmturner/goidentity/v6/go.mod
generated
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
module github.com/jcmturner/goidentity/v6
|
||||||
|
|
||||||
|
go 1.13
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/hashicorp/go-uuid v1.0.2
|
||||||
|
github.com/stretchr/testify v1.4.0
|
||||||
|
)
|
12
vendor/github.com/jcmturner/goidentity/v6/go.sum
generated
vendored
Normal file
12
vendor/github.com/jcmturner/goidentity/v6/go.sum
generated
vendored
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE=
|
||||||
|
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||||
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
52
vendor/github.com/jcmturner/goidentity/v6/identity.go
generated
vendored
Normal file
52
vendor/github.com/jcmturner/goidentity/v6/identity.go
generated
vendored
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
package goidentity
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
CTXKey = "jcmturner/goidentity"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Identity interface {
|
||||||
|
UserName() string
|
||||||
|
SetUserName(s string)
|
||||||
|
Domain() string
|
||||||
|
SetDomain(s string)
|
||||||
|
DisplayName() string
|
||||||
|
SetDisplayName(s string)
|
||||||
|
Human() bool
|
||||||
|
SetHuman(b bool)
|
||||||
|
AuthTime() time.Time
|
||||||
|
SetAuthTime(t time.Time)
|
||||||
|
AuthzAttributes() []string
|
||||||
|
AddAuthzAttribute(a string)
|
||||||
|
RemoveAuthzAttribute(a string)
|
||||||
|
Authenticated() bool
|
||||||
|
SetAuthenticated(b bool)
|
||||||
|
Authorized(a string) bool
|
||||||
|
SessionID() string
|
||||||
|
Expired() bool
|
||||||
|
Attributes() map[string]interface{}
|
||||||
|
SetAttribute(k string, v interface{})
|
||||||
|
SetAttributes(map[string]interface{})
|
||||||
|
RemoveAttribute(k string)
|
||||||
|
Marshal() ([]byte, error)
|
||||||
|
Unmarshal([]byte) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddToHTTPRequestContext(id Identity, r *http.Request) *http.Request {
|
||||||
|
ctx := r.Context()
|
||||||
|
ctx = context.WithValue(ctx, CTXKey, id)
|
||||||
|
return r.WithContext(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func FromHTTPRequestContext(r *http.Request) Identity {
|
||||||
|
ctx := r.Context()
|
||||||
|
if id, ok := ctx.Value(CTXKey).(Identity); ok {
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
172
vendor/github.com/jcmturner/goidentity/v6/user.go
generated
vendored
Normal file
172
vendor/github.com/jcmturner/goidentity/v6/user.go
generated
vendored
Normal file
|
@ -0,0 +1,172 @@
|
||||||
|
package goidentity
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/gob"
|
||||||
|
"github.com/hashicorp/go-uuid"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
authenticated bool
|
||||||
|
domain string
|
||||||
|
userName string
|
||||||
|
displayName string
|
||||||
|
email string
|
||||||
|
human bool
|
||||||
|
groupMembership map[string]bool
|
||||||
|
authTime time.Time
|
||||||
|
sessionID string
|
||||||
|
expiry time.Time
|
||||||
|
attributes map[string]interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUser(username string) User {
|
||||||
|
uuid, err := uuid.GenerateUUID()
|
||||||
|
if err != nil {
|
||||||
|
uuid = "00unique-sess-ions-uuid-unavailable0"
|
||||||
|
}
|
||||||
|
return User{
|
||||||
|
userName: username,
|
||||||
|
groupMembership: make(map[string]bool),
|
||||||
|
sessionID: uuid,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) UserName() string {
|
||||||
|
return u.userName
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) SetUserName(s string) {
|
||||||
|
u.userName = s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) Domain() string {
|
||||||
|
return u.domain
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) SetDomain(s string) {
|
||||||
|
u.domain = s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) DisplayName() string {
|
||||||
|
if u.displayName == "" {
|
||||||
|
return u.userName
|
||||||
|
}
|
||||||
|
return u.displayName
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) SetDisplayName(s string) {
|
||||||
|
u.displayName = s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) Human() bool {
|
||||||
|
return u.human
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) SetHuman(b bool) {
|
||||||
|
u.human = b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) AuthTime() time.Time {
|
||||||
|
return u.authTime
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) SetAuthTime(t time.Time) {
|
||||||
|
u.authTime = t
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) AuthzAttributes() []string {
|
||||||
|
s := make([]string, len(u.groupMembership))
|
||||||
|
i := 0
|
||||||
|
for a := range u.groupMembership {
|
||||||
|
s[i] = a
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) Authenticated() bool {
|
||||||
|
return u.authenticated
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) SetAuthenticated(b bool) {
|
||||||
|
u.authenticated = b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) AddAuthzAttribute(a string) {
|
||||||
|
u.groupMembership[a] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) RemoveAuthzAttribute(a string) {
|
||||||
|
if _, ok := u.groupMembership[a]; !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
delete(u.groupMembership, a)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) EnableAuthzAttribute(a string) {
|
||||||
|
if enabled, ok := u.groupMembership[a]; ok && !enabled {
|
||||||
|
u.groupMembership[a] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) DisableAuthzAttribute(a string) {
|
||||||
|
if enabled, ok := u.groupMembership[a]; ok && enabled {
|
||||||
|
u.groupMembership[a] = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) Authorized(a string) bool {
|
||||||
|
if enabled, ok := u.groupMembership[a]; ok && enabled {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) SessionID() string {
|
||||||
|
return u.sessionID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) SetExpiry(t time.Time) {
|
||||||
|
u.expiry = t
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) Expired() bool {
|
||||||
|
if !u.expiry.IsZero() && time.Now().UTC().After(u.expiry) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) Attributes() map[string]interface{} {
|
||||||
|
return u.attributes
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) SetAttribute(k string, v interface{}) {
|
||||||
|
u.attributes[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) SetAttributes(a map[string]interface{}) {
|
||||||
|
u.attributes = a
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) RemoveAttribute(k string) {
|
||||||
|
delete(u.attributes, k)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) Marshal() ([]byte, error) {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
enc := gob.NewEncoder(buf)
|
||||||
|
err := enc.Encode(u)
|
||||||
|
if err != nil {
|
||||||
|
return []byte{}, err
|
||||||
|
}
|
||||||
|
return buf.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) Unmarshal(b []byte) error {
|
||||||
|
buf := bytes.NewBuffer(b)
|
||||||
|
dec := gob.NewDecoder(buf)
|
||||||
|
return dec.Decode(u)
|
||||||
|
}
|
201
vendor/github.com/jcmturner/gokrb5/v8/LICENSE
generated
vendored
Normal file
201
vendor/github.com/jcmturner/gokrb5/v8/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright {yyyy} {name of copyright owner}
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
86
vendor/github.com/jcmturner/gokrb5/v8/asn1tools/tools.go
generated
vendored
Normal file
86
vendor/github.com/jcmturner/gokrb5/v8/asn1tools/tools.go
generated
vendored
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
// Package asn1tools provides tools for managing ASN1 marshaled data.
|
||||||
|
package asn1tools
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/jcmturner/gofork/encoding/asn1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MarshalLengthBytes returns the ASN1 encoded bytes for the length 'l'
|
||||||
|
//
|
||||||
|
// There are two forms: short (for lengths between 0 and 127), and long definite (for lengths between 0 and 2^1008 -1).
|
||||||
|
//
|
||||||
|
// Short form: One octet. Bit 8 has value "0" and bits 7-1 give the length.
|
||||||
|
//
|
||||||
|
// Long form: Two to 127 octets. Bit 8 of first octet has value "1" and bits 7-1 give the number of additional length octets. Second and following octets give the length, base 256, most significant digit first.
|
||||||
|
func MarshalLengthBytes(l int) []byte {
|
||||||
|
if l <= 127 {
|
||||||
|
return []byte{byte(l)}
|
||||||
|
}
|
||||||
|
var b []byte
|
||||||
|
p := 1
|
||||||
|
for i := 1; i < 127; {
|
||||||
|
b = append([]byte{byte((l % (p * 256)) / p)}, b...)
|
||||||
|
p = p * 256
|
||||||
|
l = l - l%p
|
||||||
|
if l <= 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return append([]byte{byte(128 + len(b))}, b...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetLengthFromASN returns the length of a slice of ASN1 encoded bytes from the ASN1 length header it contains.
|
||||||
|
func GetLengthFromASN(b []byte) int {
|
||||||
|
if int(b[1]) <= 127 {
|
||||||
|
return int(b[1])
|
||||||
|
}
|
||||||
|
// The bytes that indicate the length
|
||||||
|
lb := b[2 : 2+int(b[1])-128]
|
||||||
|
base := 1
|
||||||
|
l := 0
|
||||||
|
for i := len(lb) - 1; i >= 0; i-- {
|
||||||
|
l += int(lb[i]) * base
|
||||||
|
base = base * 256
|
||||||
|
}
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNumberBytesInLengthHeader returns the number of bytes in the ASn1 header that indicate the length.
|
||||||
|
func GetNumberBytesInLengthHeader(b []byte) int {
|
||||||
|
if int(b[1]) <= 127 {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
// The bytes that indicate the length
|
||||||
|
return 1 + int(b[1]) - 128
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddASNAppTag adds an ASN1 encoding application tag value to the raw bytes provided.
|
||||||
|
func AddASNAppTag(b []byte, tag int) []byte {
|
||||||
|
r := asn1.RawValue{
|
||||||
|
Class: asn1.ClassApplication,
|
||||||
|
IsCompound: true,
|
||||||
|
Tag: tag,
|
||||||
|
Bytes: b,
|
||||||
|
}
|
||||||
|
ab, _ := asn1.Marshal(r)
|
||||||
|
return ab
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// The Marshal method of golang's asn1 package does not enable you to define wrapping the output in an application tag.
|
||||||
|
// This method adds that wrapping tag.
|
||||||
|
func AddASNAppTag(b []byte, tag int) []byte {
|
||||||
|
// The ASN1 wrapping consists of 2 bytes:
|
||||||
|
// 1st byte -> Identifier Octet - Application Tag
|
||||||
|
// 2nd byte -> The length (this will be the size indicated in the input bytes + 2 for the additional bytes we add here.
|
||||||
|
// Application Tag:
|
||||||
|
//| Bit: | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 |
|
||||||
|
//| Value: | 0 | 1 | 1 | From the RFC spec 4120 |
|
||||||
|
//| Explanation | Defined by the ASN1 encoding rules for an application tag | A value of 1 indicates a constructed type | The ASN Application tag value |
|
||||||
|
// Therefore the value of the byte is an integer = ( Application tag value + 96 )
|
||||||
|
//b = append(MarshalLengthBytes(int(b[1])+2), b...)
|
||||||
|
b = append(MarshalLengthBytes(len(b)), b...)
|
||||||
|
b = append([]byte{byte(96 + tag)}, b...)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
*/
|
182
vendor/github.com/jcmturner/gokrb5/v8/client/ASExchange.go
generated
vendored
Normal file
182
vendor/github.com/jcmturner/gokrb5/v8/client/ASExchange.go
generated
vendored
Normal file
|
@ -0,0 +1,182 @@
|
||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/jcmturner/gokrb5/v8/crypto"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/crypto/etype"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/errorcode"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/keyusage"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/patype"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/krberror"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/messages"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ASExchange performs an AS exchange for the client to retrieve a TGT.
|
||||||
|
func (cl *Client) ASExchange(realm string, ASReq messages.ASReq, referral int) (messages.ASRep, error) {
|
||||||
|
if ok, err := cl.IsConfigured(); !ok {
|
||||||
|
return messages.ASRep{}, krberror.Errorf(err, krberror.ConfigError, "AS Exchange cannot be performed")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set PAData if required
|
||||||
|
err := setPAData(cl, nil, &ASReq)
|
||||||
|
if err != nil {
|
||||||
|
return messages.ASRep{}, krberror.Errorf(err, krberror.KRBMsgError, "AS Exchange Error: issue with setting PAData on AS_REQ")
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := ASReq.Marshal()
|
||||||
|
if err != nil {
|
||||||
|
return messages.ASRep{}, krberror.Errorf(err, krberror.EncodingError, "AS Exchange Error: failed marshaling AS_REQ")
|
||||||
|
}
|
||||||
|
var ASRep messages.ASRep
|
||||||
|
|
||||||
|
rb, err := cl.sendToKDC(b, realm)
|
||||||
|
if err != nil {
|
||||||
|
if e, ok := err.(messages.KRBError); ok {
|
||||||
|
switch e.ErrorCode {
|
||||||
|
case errorcode.KDC_ERR_PREAUTH_REQUIRED, errorcode.KDC_ERR_PREAUTH_FAILED:
|
||||||
|
// From now on assume this client will need to do this pre-auth and set the PAData
|
||||||
|
cl.settings.assumePreAuthentication = true
|
||||||
|
err = setPAData(cl, &e, &ASReq)
|
||||||
|
if err != nil {
|
||||||
|
return messages.ASRep{}, krberror.Errorf(err, krberror.KRBMsgError, "AS Exchange Error: failed setting AS_REQ PAData for pre-authentication required")
|
||||||
|
}
|
||||||
|
b, err := ASReq.Marshal()
|
||||||
|
if err != nil {
|
||||||
|
return messages.ASRep{}, krberror.Errorf(err, krberror.EncodingError, "AS Exchange Error: failed marshaling AS_REQ with PAData")
|
||||||
|
}
|
||||||
|
rb, err = cl.sendToKDC(b, realm)
|
||||||
|
if err != nil {
|
||||||
|
if _, ok := err.(messages.KRBError); ok {
|
||||||
|
return messages.ASRep{}, krberror.Errorf(err, krberror.KDCError, "AS Exchange Error: kerberos error response from KDC")
|
||||||
|
}
|
||||||
|
return messages.ASRep{}, krberror.Errorf(err, krberror.NetworkingError, "AS Exchange Error: failed sending AS_REQ to KDC")
|
||||||
|
}
|
||||||
|
case errorcode.KDC_ERR_WRONG_REALM:
|
||||||
|
// Client referral https://tools.ietf.org/html/rfc6806.html#section-7
|
||||||
|
if referral > 5 {
|
||||||
|
return messages.ASRep{}, krberror.Errorf(err, krberror.KRBMsgError, "maximum number of client referrals exceeded")
|
||||||
|
}
|
||||||
|
referral++
|
||||||
|
return cl.ASExchange(e.CRealm, ASReq, referral)
|
||||||
|
default:
|
||||||
|
return messages.ASRep{}, krberror.Errorf(err, krberror.KDCError, "AS Exchange Error: kerberos error response from KDC")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return messages.ASRep{}, krberror.Errorf(err, krberror.NetworkingError, "AS Exchange Error: failed sending AS_REQ to KDC")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err = ASRep.Unmarshal(rb)
|
||||||
|
if err != nil {
|
||||||
|
return messages.ASRep{}, krberror.Errorf(err, krberror.EncodingError, "AS Exchange Error: failed to process the AS_REP")
|
||||||
|
}
|
||||||
|
if ok, err := ASRep.Verify(cl.Config, cl.Credentials, ASReq); !ok {
|
||||||
|
return messages.ASRep{}, krberror.Errorf(err, krberror.KRBMsgError, "AS Exchange Error: AS_REP is not valid or client password/keytab incorrect")
|
||||||
|
}
|
||||||
|
return ASRep, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// setPAData adds pre-authentication data to the AS_REQ.
|
||||||
|
func setPAData(cl *Client, krberr *messages.KRBError, ASReq *messages.ASReq) error {
|
||||||
|
if !cl.settings.DisablePAFXFAST() {
|
||||||
|
pa := types.PAData{PADataType: patype.PA_REQ_ENC_PA_REP}
|
||||||
|
ASReq.PAData = append(ASReq.PAData, pa)
|
||||||
|
}
|
||||||
|
if cl.settings.AssumePreAuthentication() {
|
||||||
|
// Identify the etype to use to encrypt the PA Data
|
||||||
|
var et etype.EType
|
||||||
|
var err error
|
||||||
|
var key types.EncryptionKey
|
||||||
|
var kvno int
|
||||||
|
if krberr == nil {
|
||||||
|
// This is not in response to an error from the KDC. It is preemptive or renewal
|
||||||
|
// There is no KRB Error that tells us the etype to use
|
||||||
|
etn := cl.settings.preAuthEType // Use the etype that may have previously been negotiated
|
||||||
|
if etn == 0 {
|
||||||
|
etn = int32(cl.Config.LibDefaults.PreferredPreauthTypes[0]) // Resort to config
|
||||||
|
}
|
||||||
|
et, err = crypto.GetEtype(etn)
|
||||||
|
if err != nil {
|
||||||
|
return krberror.Errorf(err, krberror.EncryptingError, "error getting etype for pre-auth encryption")
|
||||||
|
}
|
||||||
|
key, kvno, err = cl.Key(et, 0, nil)
|
||||||
|
if err != nil {
|
||||||
|
return krberror.Errorf(err, krberror.EncryptingError, "error getting key from credentials")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Get the etype to use from the PA data in the KRBError e-data
|
||||||
|
et, err = preAuthEType(krberr)
|
||||||
|
if err != nil {
|
||||||
|
return krberror.Errorf(err, krberror.EncryptingError, "error getting etype for pre-auth encryption")
|
||||||
|
}
|
||||||
|
cl.settings.preAuthEType = et.GetETypeID() // Set the etype that has been defined for potential future use
|
||||||
|
key, kvno, err = cl.Key(et, 0, krberr)
|
||||||
|
if err != nil {
|
||||||
|
return krberror.Errorf(err, krberror.EncryptingError, "error getting key from credentials")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Generate the PA data
|
||||||
|
paTSb, err := types.GetPAEncTSEncAsnMarshalled()
|
||||||
|
if err != nil {
|
||||||
|
return krberror.Errorf(err, krberror.KRBMsgError, "error creating PAEncTSEnc for Pre-Authentication")
|
||||||
|
}
|
||||||
|
paEncTS, err := crypto.GetEncryptedData(paTSb, key, keyusage.AS_REQ_PA_ENC_TIMESTAMP, kvno)
|
||||||
|
if err != nil {
|
||||||
|
return krberror.Errorf(err, krberror.EncryptingError, "error encrypting pre-authentication timestamp")
|
||||||
|
}
|
||||||
|
pb, err := paEncTS.Marshal()
|
||||||
|
if err != nil {
|
||||||
|
return krberror.Errorf(err, krberror.EncodingError, "error marshaling the PAEncTSEnc encrypted data")
|
||||||
|
}
|
||||||
|
pa := types.PAData{
|
||||||
|
PADataType: patype.PA_ENC_TIMESTAMP,
|
||||||
|
PADataValue: pb,
|
||||||
|
}
|
||||||
|
// Look for and delete any exiting patype.PA_ENC_TIMESTAMP
|
||||||
|
for i, pa := range ASReq.PAData {
|
||||||
|
if pa.PADataType == patype.PA_ENC_TIMESTAMP {
|
||||||
|
ASReq.PAData[i] = ASReq.PAData[len(ASReq.PAData)-1]
|
||||||
|
ASReq.PAData = ASReq.PAData[:len(ASReq.PAData)-1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ASReq.PAData = append(ASReq.PAData, pa)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// preAuthEType establishes what encryption type to use for pre-authentication from the KRBError returned from the KDC.
|
||||||
|
func preAuthEType(krberr *messages.KRBError) (etype etype.EType, err error) {
|
||||||
|
//RFC 4120 5.2.7.5 covers the preference order of ETYPE-INFO2 and ETYPE-INFO.
|
||||||
|
var etypeID int32
|
||||||
|
var pas types.PADataSequence
|
||||||
|
e := pas.Unmarshal(krberr.EData)
|
||||||
|
if e != nil {
|
||||||
|
err = krberror.Errorf(e, krberror.EncodingError, "error unmashalling KRBError data")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
Loop:
|
||||||
|
for _, pa := range pas {
|
||||||
|
switch pa.PADataType {
|
||||||
|
case patype.PA_ETYPE_INFO2:
|
||||||
|
info, e := pa.GetETypeInfo2()
|
||||||
|
if e != nil {
|
||||||
|
err = krberror.Errorf(e, krberror.EncodingError, "error unmashalling ETYPE-INFO2 data")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
etypeID = info[0].EType
|
||||||
|
break Loop
|
||||||
|
case patype.PA_ETYPE_INFO:
|
||||||
|
info, e := pa.GetETypeInfo()
|
||||||
|
if e != nil {
|
||||||
|
err = krberror.Errorf(e, krberror.EncodingError, "error unmashalling ETYPE-INFO data")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
etypeID = info[0].EType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
etype, e = crypto.GetEtype(etypeID)
|
||||||
|
if e != nil {
|
||||||
|
err = krberror.Errorf(e, krberror.EncryptingError, "error creating etype")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return etype, nil
|
||||||
|
}
|
103
vendor/github.com/jcmturner/gokrb5/v8/client/TGSExchange.go
generated
vendored
Normal file
103
vendor/github.com/jcmturner/gokrb5/v8/client/TGSExchange.go
generated
vendored
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/flags"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/nametype"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/krberror"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/messages"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TGSREQGenerateAndExchange generates the TGS_REQ and performs a TGS exchange to retrieve a ticket to the specified SPN.
|
||||||
|
func (cl *Client) TGSREQGenerateAndExchange(spn types.PrincipalName, kdcRealm string, tgt messages.Ticket, sessionKey types.EncryptionKey, renewal bool) (tgsReq messages.TGSReq, tgsRep messages.TGSRep, err error) {
|
||||||
|
tgsReq, err = messages.NewTGSReq(cl.Credentials.CName(), kdcRealm, cl.Config, tgt, sessionKey, spn, renewal)
|
||||||
|
if err != nil {
|
||||||
|
return tgsReq, tgsRep, krberror.Errorf(err, krberror.KRBMsgError, "TGS Exchange Error: failed to generate a new TGS_REQ")
|
||||||
|
}
|
||||||
|
return cl.TGSExchange(tgsReq, kdcRealm, tgsRep.Ticket, sessionKey, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TGSExchange exchanges the provided TGS_REQ with the KDC to retrieve a TGS_REP.
|
||||||
|
// Referrals are automatically handled.
|
||||||
|
// The client's cache is updated with the ticket received.
|
||||||
|
func (cl *Client) TGSExchange(tgsReq messages.TGSReq, kdcRealm string, tgt messages.Ticket, sessionKey types.EncryptionKey, referral int) (messages.TGSReq, messages.TGSRep, error) {
|
||||||
|
var tgsRep messages.TGSRep
|
||||||
|
b, err := tgsReq.Marshal()
|
||||||
|
if err != nil {
|
||||||
|
return tgsReq, tgsRep, krberror.Errorf(err, krberror.EncodingError, "TGS Exchange Error: failed to marshal TGS_REQ")
|
||||||
|
}
|
||||||
|
r, err := cl.sendToKDC(b, kdcRealm)
|
||||||
|
if err != nil {
|
||||||
|
if _, ok := err.(messages.KRBError); ok {
|
||||||
|
return tgsReq, tgsRep, krberror.Errorf(err, krberror.KDCError, "TGS Exchange Error: kerberos error response from KDC when requesting for %s", tgsReq.ReqBody.SName.PrincipalNameString())
|
||||||
|
}
|
||||||
|
return tgsReq, tgsRep, krberror.Errorf(err, krberror.NetworkingError, "TGS Exchange Error: issue sending TGS_REQ to KDC")
|
||||||
|
}
|
||||||
|
err = tgsRep.Unmarshal(r)
|
||||||
|
if err != nil {
|
||||||
|
return tgsReq, tgsRep, krberror.Errorf(err, krberror.EncodingError, "TGS Exchange Error: failed to process the TGS_REP")
|
||||||
|
}
|
||||||
|
err = tgsRep.DecryptEncPart(sessionKey)
|
||||||
|
if err != nil {
|
||||||
|
return tgsReq, tgsRep, krberror.Errorf(err, krberror.EncodingError, "TGS Exchange Error: failed to process the TGS_REP")
|
||||||
|
}
|
||||||
|
if ok, err := tgsRep.Verify(cl.Config, tgsReq); !ok {
|
||||||
|
return tgsReq, tgsRep, krberror.Errorf(err, krberror.EncodingError, "TGS Exchange Error: TGS_REP is not valid")
|
||||||
|
}
|
||||||
|
|
||||||
|
if tgsRep.Ticket.SName.NameString[0] == "krbtgt" && !tgsRep.Ticket.SName.Equal(tgsReq.ReqBody.SName) {
|
||||||
|
if referral > 5 {
|
||||||
|
return tgsReq, tgsRep, krberror.Errorf(err, krberror.KRBMsgError, "TGS Exchange Error: maximum number of referrals exceeded")
|
||||||
|
}
|
||||||
|
// Server referral https://tools.ietf.org/html/rfc6806.html#section-8
|
||||||
|
// The TGS Rep contains a TGT for another domain as the service resides in that domain.
|
||||||
|
cl.addSession(tgsRep.Ticket, tgsRep.DecryptedEncPart)
|
||||||
|
realm := tgsRep.Ticket.SName.NameString[len(tgsRep.Ticket.SName.NameString)-1]
|
||||||
|
referral++
|
||||||
|
if types.IsFlagSet(&tgsReq.ReqBody.KDCOptions, flags.EncTktInSkey) && len(tgsReq.ReqBody.AdditionalTickets) > 0 {
|
||||||
|
tgsReq, err = messages.NewUser2UserTGSReq(cl.Credentials.CName(), kdcRealm, cl.Config, tgt, sessionKey, tgsReq.ReqBody.SName, tgsReq.Renewal, tgsReq.ReqBody.AdditionalTickets[0])
|
||||||
|
if err != nil {
|
||||||
|
return tgsReq, tgsRep, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tgsReq, err = messages.NewTGSReq(cl.Credentials.CName(), realm, cl.Config, tgsRep.Ticket, tgsRep.DecryptedEncPart.Key, tgsReq.ReqBody.SName, tgsReq.Renewal)
|
||||||
|
if err != nil {
|
||||||
|
return tgsReq, tgsRep, err
|
||||||
|
}
|
||||||
|
return cl.TGSExchange(tgsReq, realm, tgsRep.Ticket, tgsRep.DecryptedEncPart.Key, referral)
|
||||||
|
}
|
||||||
|
cl.cache.addEntry(
|
||||||
|
tgsRep.Ticket,
|
||||||
|
tgsRep.DecryptedEncPart.AuthTime,
|
||||||
|
tgsRep.DecryptedEncPart.StartTime,
|
||||||
|
tgsRep.DecryptedEncPart.EndTime,
|
||||||
|
tgsRep.DecryptedEncPart.RenewTill,
|
||||||
|
tgsRep.DecryptedEncPart.Key,
|
||||||
|
)
|
||||||
|
cl.Log("ticket added to cache for %s (EndTime: %v)", tgsRep.Ticket.SName.PrincipalNameString(), tgsRep.DecryptedEncPart.EndTime)
|
||||||
|
return tgsReq, tgsRep, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetServiceTicket makes a request to get a service ticket for the SPN specified
|
||||||
|
// SPN format: <SERVICE>/<FQDN> Eg. HTTP/www.example.com
|
||||||
|
// The ticket will be added to the client's ticket cache
|
||||||
|
func (cl *Client) GetServiceTicket(spn string) (messages.Ticket, types.EncryptionKey, error) {
|
||||||
|
var tkt messages.Ticket
|
||||||
|
var skey types.EncryptionKey
|
||||||
|
if tkt, skey, ok := cl.GetCachedTicket(spn); ok {
|
||||||
|
// Already a valid ticket in the cache
|
||||||
|
return tkt, skey, nil
|
||||||
|
}
|
||||||
|
princ := types.NewPrincipalName(nametype.KRB_NT_PRINCIPAL, spn)
|
||||||
|
realm := cl.Config.ResolveRealm(princ.NameString[len(princ.NameString)-1])
|
||||||
|
|
||||||
|
tgt, skey, err := cl.sessionTGT(realm)
|
||||||
|
if err != nil {
|
||||||
|
return tkt, skey, err
|
||||||
|
}
|
||||||
|
_, tgsRep, err := cl.TGSREQGenerateAndExchange(princ, realm, tgt, skey, false)
|
||||||
|
if err != nil {
|
||||||
|
return tkt, skey, err
|
||||||
|
}
|
||||||
|
return tgsRep.Ticket, tgsRep.DecryptedEncPart.Key, nil
|
||||||
|
}
|
134
vendor/github.com/jcmturner/gokrb5/v8/client/cache.go
generated
vendored
Normal file
134
vendor/github.com/jcmturner/gokrb5/v8/client/cache.go
generated
vendored
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"sort"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/jcmturner/gokrb5/v8/messages"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Cache for service tickets held by the client.
|
||||||
|
type Cache struct {
|
||||||
|
Entries map[string]CacheEntry
|
||||||
|
mux sync.RWMutex
|
||||||
|
}
|
||||||
|
|
||||||
|
// CacheEntry holds details for a cache entry.
|
||||||
|
type CacheEntry struct {
|
||||||
|
SPN string
|
||||||
|
Ticket messages.Ticket `json:"-"`
|
||||||
|
AuthTime time.Time
|
||||||
|
StartTime time.Time
|
||||||
|
EndTime time.Time
|
||||||
|
RenewTill time.Time
|
||||||
|
SessionKey types.EncryptionKey `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCache creates a new client ticket cache instance.
|
||||||
|
func NewCache() *Cache {
|
||||||
|
return &Cache{
|
||||||
|
Entries: map[string]CacheEntry{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// getEntry returns a cache entry that matches the SPN.
|
||||||
|
func (c *Cache) getEntry(spn string) (CacheEntry, bool) {
|
||||||
|
c.mux.RLock()
|
||||||
|
defer c.mux.RUnlock()
|
||||||
|
e, ok := (*c).Entries[spn]
|
||||||
|
return e, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// JSON returns information about the cached service tickets in a JSON format.
|
||||||
|
func (c *Cache) JSON() (string, error) {
|
||||||
|
c.mux.RLock()
|
||||||
|
defer c.mux.RUnlock()
|
||||||
|
var es []CacheEntry
|
||||||
|
keys := make([]string, 0, len(c.Entries))
|
||||||
|
for k := range c.Entries {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
sort.Strings(keys)
|
||||||
|
for _, k := range keys {
|
||||||
|
es = append(es, c.Entries[k])
|
||||||
|
}
|
||||||
|
b, err := json.MarshalIndent(&es, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(b), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// addEntry adds a ticket to the cache.
|
||||||
|
func (c *Cache) addEntry(tkt messages.Ticket, authTime, startTime, endTime, renewTill time.Time, sessionKey types.EncryptionKey) CacheEntry {
|
||||||
|
spn := tkt.SName.PrincipalNameString()
|
||||||
|
c.mux.Lock()
|
||||||
|
defer c.mux.Unlock()
|
||||||
|
(*c).Entries[spn] = CacheEntry{
|
||||||
|
SPN: spn,
|
||||||
|
Ticket: tkt,
|
||||||
|
AuthTime: authTime,
|
||||||
|
StartTime: startTime,
|
||||||
|
EndTime: endTime,
|
||||||
|
RenewTill: renewTill,
|
||||||
|
SessionKey: sessionKey,
|
||||||
|
}
|
||||||
|
return c.Entries[spn]
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear deletes all the cache entries
|
||||||
|
func (c *Cache) clear() {
|
||||||
|
c.mux.Lock()
|
||||||
|
defer c.mux.Unlock()
|
||||||
|
for k := range c.Entries {
|
||||||
|
delete(c.Entries, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveEntry removes the cache entry for the defined SPN.
|
||||||
|
func (c *Cache) RemoveEntry(spn string) {
|
||||||
|
c.mux.Lock()
|
||||||
|
defer c.mux.Unlock()
|
||||||
|
delete(c.Entries, spn)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCachedTicket returns a ticket from the cache for the SPN.
|
||||||
|
// Only a ticket that is currently valid will be returned.
|
||||||
|
func (cl *Client) GetCachedTicket(spn string) (messages.Ticket, types.EncryptionKey, bool) {
|
||||||
|
if e, ok := cl.cache.getEntry(spn); ok {
|
||||||
|
//If within time window of ticket return it
|
||||||
|
if time.Now().UTC().After(e.StartTime) && time.Now().UTC().Before(e.EndTime) {
|
||||||
|
cl.Log("ticket received from cache for %s", spn)
|
||||||
|
return e.Ticket, e.SessionKey, true
|
||||||
|
} else if time.Now().UTC().Before(e.RenewTill) {
|
||||||
|
e, err := cl.renewTicket(e)
|
||||||
|
if err != nil {
|
||||||
|
return e.Ticket, e.SessionKey, false
|
||||||
|
}
|
||||||
|
return e.Ticket, e.SessionKey, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var tkt messages.Ticket
|
||||||
|
var key types.EncryptionKey
|
||||||
|
return tkt, key, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// renewTicket renews a cache entry ticket.
|
||||||
|
// To renew from outside the client package use GetCachedTicket
|
||||||
|
func (cl *Client) renewTicket(e CacheEntry) (CacheEntry, error) {
|
||||||
|
spn := e.Ticket.SName
|
||||||
|
_, _, err := cl.TGSREQGenerateAndExchange(spn, e.Ticket.Realm, e.Ticket, e.SessionKey, true)
|
||||||
|
if err != nil {
|
||||||
|
return e, err
|
||||||
|
}
|
||||||
|
e, ok := cl.cache.getEntry(e.Ticket.SName.PrincipalNameString())
|
||||||
|
if !ok {
|
||||||
|
return e, errors.New("ticket was not added to cache")
|
||||||
|
}
|
||||||
|
cl.Log("ticket renewed for %s (EndTime: %v)", spn.PrincipalNameString(), e.EndTime)
|
||||||
|
return e, nil
|
||||||
|
}
|
329
vendor/github.com/jcmturner/gokrb5/v8/client/client.go
generated
vendored
Normal file
329
vendor/github.com/jcmturner/gokrb5/v8/client/client.go
generated
vendored
Normal file
|
@ -0,0 +1,329 @@
|
||||||
|
// Package client provides a client library and methods for Kerberos 5 authentication.
|
||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/jcmturner/gokrb5/v8/config"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/credentials"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/crypto"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/crypto/etype"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/errorcode"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/nametype"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/keytab"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/krberror"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/messages"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Client side configuration and state.
|
||||||
|
type Client struct {
|
||||||
|
Credentials *credentials.Credentials
|
||||||
|
Config *config.Config
|
||||||
|
settings *Settings
|
||||||
|
sessions *sessions
|
||||||
|
cache *Cache
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewWithPassword creates a new client from a password credential.
|
||||||
|
// Set the realm to empty string to use the default realm from config.
|
||||||
|
func NewWithPassword(username, realm, password string, krb5conf *config.Config, settings ...func(*Settings)) *Client {
|
||||||
|
creds := credentials.New(username, realm)
|
||||||
|
return &Client{
|
||||||
|
Credentials: creds.WithPassword(password),
|
||||||
|
Config: krb5conf,
|
||||||
|
settings: NewSettings(settings...),
|
||||||
|
sessions: &sessions{
|
||||||
|
Entries: make(map[string]*session),
|
||||||
|
},
|
||||||
|
cache: NewCache(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewWithKeytab creates a new client from a keytab credential.
|
||||||
|
func NewWithKeytab(username, realm string, kt *keytab.Keytab, krb5conf *config.Config, settings ...func(*Settings)) *Client {
|
||||||
|
creds := credentials.New(username, realm)
|
||||||
|
return &Client{
|
||||||
|
Credentials: creds.WithKeytab(kt),
|
||||||
|
Config: krb5conf,
|
||||||
|
settings: NewSettings(settings...),
|
||||||
|
sessions: &sessions{
|
||||||
|
Entries: make(map[string]*session),
|
||||||
|
},
|
||||||
|
cache: NewCache(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFromCCache create a client from a populated client cache.
|
||||||
|
//
|
||||||
|
// WARNING: A client created from CCache does not automatically renew TGTs and a failure will occur after the TGT expires.
|
||||||
|
func NewFromCCache(c *credentials.CCache, krb5conf *config.Config, settings ...func(*Settings)) (*Client, error) {
|
||||||
|
cl := &Client{
|
||||||
|
Credentials: c.GetClientCredentials(),
|
||||||
|
Config: krb5conf,
|
||||||
|
settings: NewSettings(settings...),
|
||||||
|
sessions: &sessions{
|
||||||
|
Entries: make(map[string]*session),
|
||||||
|
},
|
||||||
|
cache: NewCache(),
|
||||||
|
}
|
||||||
|
spn := types.PrincipalName{
|
||||||
|
NameType: nametype.KRB_NT_SRV_INST,
|
||||||
|
NameString: []string{"krbtgt", c.DefaultPrincipal.Realm},
|
||||||
|
}
|
||||||
|
cred, ok := c.GetEntry(spn)
|
||||||
|
if !ok {
|
||||||
|
return cl, errors.New("TGT not found in CCache")
|
||||||
|
}
|
||||||
|
var tgt messages.Ticket
|
||||||
|
err := tgt.Unmarshal(cred.Ticket)
|
||||||
|
if err != nil {
|
||||||
|
return cl, fmt.Errorf("TGT bytes in cache are not valid: %v", err)
|
||||||
|
}
|
||||||
|
cl.sessions.Entries[c.DefaultPrincipal.Realm] = &session{
|
||||||
|
realm: c.DefaultPrincipal.Realm,
|
||||||
|
authTime: cred.AuthTime,
|
||||||
|
endTime: cred.EndTime,
|
||||||
|
renewTill: cred.RenewTill,
|
||||||
|
tgt: tgt,
|
||||||
|
sessionKey: cred.Key,
|
||||||
|
}
|
||||||
|
for _, cred := range c.GetEntries() {
|
||||||
|
var tkt messages.Ticket
|
||||||
|
err = tkt.Unmarshal(cred.Ticket)
|
||||||
|
if err != nil {
|
||||||
|
return cl, fmt.Errorf("cache entry ticket bytes are not valid: %v", err)
|
||||||
|
}
|
||||||
|
cl.cache.addEntry(
|
||||||
|
tkt,
|
||||||
|
cred.AuthTime,
|
||||||
|
cred.StartTime,
|
||||||
|
cred.EndTime,
|
||||||
|
cred.RenewTill,
|
||||||
|
cred.Key,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return cl, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Key returns the client's encryption key for the specified encryption type and its kvno (kvno of zero will find latest).
|
||||||
|
// The key can be retrieved either from the keytab or generated from the client's password.
|
||||||
|
// If the client has both a keytab and a password defined the keytab is favoured as the source for the key
|
||||||
|
// A KRBError can be passed in the event the KDC returns one of type KDC_ERR_PREAUTH_REQUIRED and is required to derive
|
||||||
|
// the key for pre-authentication from the client's password. If a KRBError is not available, pass nil to this argument.
|
||||||
|
func (cl *Client) Key(etype etype.EType, kvno int, krberr *messages.KRBError) (types.EncryptionKey, int, error) {
|
||||||
|
if cl.Credentials.HasKeytab() && etype != nil {
|
||||||
|
return cl.Credentials.Keytab().GetEncryptionKey(cl.Credentials.CName(), cl.Credentials.Domain(), kvno, etype.GetETypeID())
|
||||||
|
} else if cl.Credentials.HasPassword() {
|
||||||
|
if krberr != nil && krberr.ErrorCode == errorcode.KDC_ERR_PREAUTH_REQUIRED {
|
||||||
|
var pas types.PADataSequence
|
||||||
|
err := pas.Unmarshal(krberr.EData)
|
||||||
|
if err != nil {
|
||||||
|
return types.EncryptionKey{}, 0, fmt.Errorf("could not get PAData from KRBError to generate key from password: %v", err)
|
||||||
|
}
|
||||||
|
key, _, err := crypto.GetKeyFromPassword(cl.Credentials.Password(), krberr.CName, krberr.CRealm, etype.GetETypeID(), pas)
|
||||||
|
return key, 0, err
|
||||||
|
}
|
||||||
|
key, _, err := crypto.GetKeyFromPassword(cl.Credentials.Password(), cl.Credentials.CName(), cl.Credentials.Domain(), etype.GetETypeID(), types.PADataSequence{})
|
||||||
|
return key, 0, err
|
||||||
|
}
|
||||||
|
return types.EncryptionKey{}, 0, errors.New("credential has neither keytab or password to generate key")
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsConfigured indicates if the client has the values required set.
|
||||||
|
func (cl *Client) IsConfigured() (bool, error) {
|
||||||
|
if cl.Credentials.UserName() == "" {
|
||||||
|
return false, errors.New("client does not have a username")
|
||||||
|
}
|
||||||
|
if cl.Credentials.Domain() == "" {
|
||||||
|
return false, errors.New("client does not have a define realm")
|
||||||
|
}
|
||||||
|
// Client needs to have either a password, keytab or a session already (later when loading from CCache)
|
||||||
|
if !cl.Credentials.HasPassword() && !cl.Credentials.HasKeytab() {
|
||||||
|
authTime, _, _, _, err := cl.sessionTimes(cl.Credentials.Domain())
|
||||||
|
if err != nil || authTime.IsZero() {
|
||||||
|
return false, errors.New("client has neither a keytab nor a password set and no session")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !cl.Config.LibDefaults.DNSLookupKDC {
|
||||||
|
for _, r := range cl.Config.Realms {
|
||||||
|
if r.Realm == cl.Credentials.Domain() {
|
||||||
|
if len(r.KDC) > 0 {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
return false, errors.New("client krb5 config does not have any defined KDCs for the default realm")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Login the client with the KDC via an AS exchange.
|
||||||
|
func (cl *Client) Login() error {
|
||||||
|
if ok, err := cl.IsConfigured(); !ok {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !cl.Credentials.HasPassword() && !cl.Credentials.HasKeytab() {
|
||||||
|
_, endTime, _, _, err := cl.sessionTimes(cl.Credentials.Domain())
|
||||||
|
if err != nil {
|
||||||
|
return krberror.Errorf(err, krberror.KRBMsgError, "no user credentials available and error getting any existing session")
|
||||||
|
}
|
||||||
|
if time.Now().UTC().After(endTime) {
|
||||||
|
return krberror.New(krberror.KRBMsgError, "cannot login, no user credentials available and no valid existing session")
|
||||||
|
}
|
||||||
|
// no credentials but there is a session with tgt already
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
ASReq, err := messages.NewASReqForTGT(cl.Credentials.Domain(), cl.Config, cl.Credentials.CName())
|
||||||
|
if err != nil {
|
||||||
|
return krberror.Errorf(err, krberror.KRBMsgError, "error generating new AS_REQ")
|
||||||
|
}
|
||||||
|
ASRep, err := cl.ASExchange(cl.Credentials.Domain(), ASReq, 0)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
cl.addSession(ASRep.Ticket, ASRep.DecryptedEncPart)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AffirmLogin will only perform an AS exchange with the KDC if the client does not already have a TGT.
|
||||||
|
func (cl *Client) AffirmLogin() error {
|
||||||
|
_, endTime, _, _, err := cl.sessionTimes(cl.Credentials.Domain())
|
||||||
|
if err != nil || time.Now().UTC().After(endTime) {
|
||||||
|
err := cl.Login()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not get valid TGT for client's realm: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// realmLogin obtains or renews a TGT and establishes a session for the realm specified.
|
||||||
|
func (cl *Client) realmLogin(realm string) error {
|
||||||
|
if realm == cl.Credentials.Domain() {
|
||||||
|
return cl.Login()
|
||||||
|
}
|
||||||
|
_, endTime, _, _, err := cl.sessionTimes(cl.Credentials.Domain())
|
||||||
|
if err != nil || time.Now().UTC().After(endTime) {
|
||||||
|
err := cl.Login()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not get valid TGT for client's realm: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tgt, skey, err := cl.sessionTGT(cl.Credentials.Domain())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
spn := types.PrincipalName{
|
||||||
|
NameType: nametype.KRB_NT_SRV_INST,
|
||||||
|
NameString: []string{"krbtgt", realm},
|
||||||
|
}
|
||||||
|
|
||||||
|
_, tgsRep, err := cl.TGSREQGenerateAndExchange(spn, cl.Credentials.Domain(), tgt, skey, false)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
cl.addSession(tgsRep.Ticket, tgsRep.DecryptedEncPart)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroy stops the auto-renewal of all sessions and removes the sessions and cache entries from the client.
|
||||||
|
func (cl *Client) Destroy() {
|
||||||
|
creds := credentials.New("", "")
|
||||||
|
cl.sessions.destroy()
|
||||||
|
cl.cache.clear()
|
||||||
|
cl.Credentials = creds
|
||||||
|
cl.Log("client destroyed")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Diagnostics runs a set of checks that the client is properly configured and writes details to the io.Writer provided.
|
||||||
|
func (cl *Client) Diagnostics(w io.Writer) error {
|
||||||
|
cl.Print(w)
|
||||||
|
var errs []string
|
||||||
|
if cl.Credentials.HasKeytab() {
|
||||||
|
var loginRealmEncTypes []int32
|
||||||
|
for _, e := range cl.Credentials.Keytab().Entries {
|
||||||
|
if e.Principal.Realm == cl.Credentials.Realm() {
|
||||||
|
loginRealmEncTypes = append(loginRealmEncTypes, e.Key.KeyType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, et := range cl.Config.LibDefaults.DefaultTktEnctypeIDs {
|
||||||
|
var etInKt bool
|
||||||
|
for _, val := range loginRealmEncTypes {
|
||||||
|
if val == et {
|
||||||
|
etInKt = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !etInKt {
|
||||||
|
errs = append(errs, fmt.Sprintf("default_tkt_enctypes specifies %d but this enctype is not available in the client's keytab", et))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, et := range cl.Config.LibDefaults.PreferredPreauthTypes {
|
||||||
|
var etInKt bool
|
||||||
|
for _, val := range loginRealmEncTypes {
|
||||||
|
if int(val) == et {
|
||||||
|
etInKt = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !etInKt {
|
||||||
|
errs = append(errs, fmt.Sprintf("preferred_preauth_types specifies %d but this enctype is not available in the client's keytab", et))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
udpCnt, udpKDC, err := cl.Config.GetKDCs(cl.Credentials.Realm(), false)
|
||||||
|
if err != nil {
|
||||||
|
errs = append(errs, fmt.Sprintf("error when resolving KDCs for UDP communication: %v", err))
|
||||||
|
}
|
||||||
|
if udpCnt < 1 {
|
||||||
|
errs = append(errs, "no KDCs resolved for communication via UDP.")
|
||||||
|
} else {
|
||||||
|
b, _ := json.MarshalIndent(&udpKDC, "", " ")
|
||||||
|
fmt.Fprintf(w, "UDP KDCs: %s\n", string(b))
|
||||||
|
}
|
||||||
|
tcpCnt, tcpKDC, err := cl.Config.GetKDCs(cl.Credentials.Realm(), false)
|
||||||
|
if err != nil {
|
||||||
|
errs = append(errs, fmt.Sprintf("error when resolving KDCs for TCP communication: %v", err))
|
||||||
|
}
|
||||||
|
if tcpCnt < 1 {
|
||||||
|
errs = append(errs, "no KDCs resolved for communication via TCP.")
|
||||||
|
} else {
|
||||||
|
b, _ := json.MarshalIndent(&tcpKDC, "", " ")
|
||||||
|
fmt.Fprintf(w, "TCP KDCs: %s\n", string(b))
|
||||||
|
}
|
||||||
|
|
||||||
|
if errs == nil || len(errs) < 1 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
err = fmt.Errorf(strings.Join(errs, "\n"))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print writes the details of the client to the io.Writer provided.
|
||||||
|
func (cl *Client) Print(w io.Writer) {
|
||||||
|
c, _ := cl.Credentials.JSON()
|
||||||
|
fmt.Fprintf(w, "Credentials:\n%s\n", c)
|
||||||
|
|
||||||
|
s, _ := cl.sessions.JSON()
|
||||||
|
fmt.Fprintf(w, "TGT Sessions:\n%s\n", s)
|
||||||
|
|
||||||
|
c, _ = cl.cache.JSON()
|
||||||
|
fmt.Fprintf(w, "Service ticket cache:\n%s\n", c)
|
||||||
|
|
||||||
|
s, _ = cl.settings.JSON()
|
||||||
|
fmt.Fprintf(w, "Settings:\n%s\n", s)
|
||||||
|
|
||||||
|
j, _ := cl.Config.JSON()
|
||||||
|
fmt.Fprintf(w, "Krb5 config:\n%s\n", j)
|
||||||
|
|
||||||
|
k, _ := cl.Credentials.Keytab().JSON()
|
||||||
|
fmt.Fprintf(w, "Keytab:\n%s\n", k)
|
||||||
|
}
|
213
vendor/github.com/jcmturner/gokrb5/v8/client/network.go
generated
vendored
Normal file
213
vendor/github.com/jcmturner/gokrb5/v8/client/network.go
generated
vendored
Normal file
|
@ -0,0 +1,213 @@
|
||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/errorcode"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/messages"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SendToKDC performs network actions to send data to the KDC.
|
||||||
|
func (cl *Client) sendToKDC(b []byte, realm string) ([]byte, error) {
|
||||||
|
var rb []byte
|
||||||
|
if cl.Config.LibDefaults.UDPPreferenceLimit == 1 {
|
||||||
|
//1 means we should always use TCP
|
||||||
|
rb, errtcp := cl.sendKDCTCP(realm, b)
|
||||||
|
if errtcp != nil {
|
||||||
|
if e, ok := errtcp.(messages.KRBError); ok {
|
||||||
|
return rb, e
|
||||||
|
}
|
||||||
|
return rb, fmt.Errorf("communication error with KDC via TCP: %v", errtcp)
|
||||||
|
}
|
||||||
|
return rb, nil
|
||||||
|
}
|
||||||
|
if len(b) <= cl.Config.LibDefaults.UDPPreferenceLimit {
|
||||||
|
//Try UDP first, TCP second
|
||||||
|
rb, errudp := cl.sendKDCUDP(realm, b)
|
||||||
|
if errudp != nil {
|
||||||
|
if e, ok := errudp.(messages.KRBError); ok && e.ErrorCode != errorcode.KRB_ERR_RESPONSE_TOO_BIG {
|
||||||
|
// Got a KRBError from KDC
|
||||||
|
// If this is not a KRB_ERR_RESPONSE_TOO_BIG we will return immediately otherwise will try TCP.
|
||||||
|
return rb, e
|
||||||
|
}
|
||||||
|
// Try TCP
|
||||||
|
r, errtcp := cl.sendKDCTCP(realm, b)
|
||||||
|
if errtcp != nil {
|
||||||
|
if e, ok := errtcp.(messages.KRBError); ok {
|
||||||
|
// Got a KRBError
|
||||||
|
return r, e
|
||||||
|
}
|
||||||
|
return r, fmt.Errorf("failed to communicate with KDC. Attempts made with UDP (%v) and then TCP (%v)", errudp, errtcp)
|
||||||
|
}
|
||||||
|
rb = r
|
||||||
|
}
|
||||||
|
return rb, nil
|
||||||
|
}
|
||||||
|
//Try TCP first, UDP second
|
||||||
|
rb, errtcp := cl.sendKDCTCP(realm, b)
|
||||||
|
if errtcp != nil {
|
||||||
|
if e, ok := errtcp.(messages.KRBError); ok {
|
||||||
|
// Got a KRBError from KDC so returning and not trying UDP.
|
||||||
|
return rb, e
|
||||||
|
}
|
||||||
|
rb, errudp := cl.sendKDCUDP(realm, b)
|
||||||
|
if errudp != nil {
|
||||||
|
if e, ok := errudp.(messages.KRBError); ok {
|
||||||
|
// Got a KRBError
|
||||||
|
return rb, e
|
||||||
|
}
|
||||||
|
return rb, fmt.Errorf("failed to communicate with KDC. Attempts made with TCP (%v) and then UDP (%v)", errtcp, errudp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rb, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// dialKDCTCP establishes a UDP connection to a KDC.
|
||||||
|
func dialKDCUDP(count int, kdcs map[int]string) (*net.UDPConn, error) {
|
||||||
|
i := 1
|
||||||
|
for i <= count {
|
||||||
|
udpAddr, err := net.ResolveUDPAddr("udp", kdcs[i])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error resolving KDC address: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, err := net.DialTimeout("udp", udpAddr.String(), 5*time.Second)
|
||||||
|
if err == nil {
|
||||||
|
if err := conn.SetDeadline(time.Now().Add(5 * time.Second)); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// conn is guaranteed to be a UDPConn
|
||||||
|
return conn.(*net.UDPConn), nil
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
return nil, errors.New("error in getting a UDP connection to any of the KDCs")
|
||||||
|
}
|
||||||
|
|
||||||
|
// dialKDCTCP establishes a TCP connection to a KDC.
|
||||||
|
func dialKDCTCP(count int, kdcs map[int]string) (*net.TCPConn, error) {
|
||||||
|
i := 1
|
||||||
|
for i <= count {
|
||||||
|
tcpAddr, err := net.ResolveTCPAddr("tcp", kdcs[i])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error resolving KDC address: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, err := net.DialTimeout("tcp", tcpAddr.String(), 5*time.Second)
|
||||||
|
if err == nil {
|
||||||
|
if err := conn.SetDeadline(time.Now().Add(5 * time.Second)); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// conn is guaranteed to be a TCPConn
|
||||||
|
return conn.(*net.TCPConn), nil
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
return nil, errors.New("error in getting a TCP connection to any of the KDCs")
|
||||||
|
}
|
||||||
|
|
||||||
|
// sendKDCUDP sends bytes to the KDC via UDP.
|
||||||
|
func (cl *Client) sendKDCUDP(realm string, b []byte) ([]byte, error) {
|
||||||
|
var r []byte
|
||||||
|
count, kdcs, err := cl.Config.GetKDCs(realm, false)
|
||||||
|
if err != nil {
|
||||||
|
return r, err
|
||||||
|
}
|
||||||
|
conn, err := dialKDCUDP(count, kdcs)
|
||||||
|
if err != nil {
|
||||||
|
return r, err
|
||||||
|
}
|
||||||
|
r, err = cl.sendUDP(conn, b)
|
||||||
|
if err != nil {
|
||||||
|
return r, err
|
||||||
|
}
|
||||||
|
return checkForKRBError(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// sendKDCTCP sends bytes to the KDC via TCP.
|
||||||
|
func (cl *Client) sendKDCTCP(realm string, b []byte) ([]byte, error) {
|
||||||
|
var r []byte
|
||||||
|
count, kdcs, err := cl.Config.GetKDCs(realm, true)
|
||||||
|
if err != nil {
|
||||||
|
return r, err
|
||||||
|
}
|
||||||
|
conn, err := dialKDCTCP(count, kdcs)
|
||||||
|
if err != nil {
|
||||||
|
return r, err
|
||||||
|
}
|
||||||
|
rb, err := cl.sendTCP(conn, b)
|
||||||
|
if err != nil {
|
||||||
|
return r, err
|
||||||
|
}
|
||||||
|
return checkForKRBError(rb)
|
||||||
|
}
|
||||||
|
|
||||||
|
// sendUDP sends bytes to connection over UDP.
|
||||||
|
func (cl *Client) sendUDP(conn *net.UDPConn, b []byte) ([]byte, error) {
|
||||||
|
var r []byte
|
||||||
|
defer conn.Close()
|
||||||
|
_, err := conn.Write(b)
|
||||||
|
if err != nil {
|
||||||
|
return r, fmt.Errorf("error sending to (%s): %v", conn.RemoteAddr().String(), err)
|
||||||
|
}
|
||||||
|
udpbuf := make([]byte, 4096)
|
||||||
|
n, _, err := conn.ReadFrom(udpbuf)
|
||||||
|
r = udpbuf[:n]
|
||||||
|
if err != nil {
|
||||||
|
return r, fmt.Errorf("sending over UDP failed to %s: %v", conn.RemoteAddr().String(), err)
|
||||||
|
}
|
||||||
|
if len(r) < 1 {
|
||||||
|
return r, fmt.Errorf("no response data from %s", conn.RemoteAddr().String())
|
||||||
|
}
|
||||||
|
return r, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// sendTCP sends bytes to connection over TCP.
|
||||||
|
func (cl *Client) sendTCP(conn *net.TCPConn, b []byte) ([]byte, error) {
|
||||||
|
defer conn.Close()
|
||||||
|
var r []byte
|
||||||
|
// RFC 4120 7.2.2 specifies the first 4 bytes indicate the length of the message in big endian order.
|
||||||
|
var buf bytes.Buffer
|
||||||
|
err := binary.Write(&buf, binary.BigEndian, uint32(len(b)))
|
||||||
|
if err != nil {
|
||||||
|
return r, err
|
||||||
|
}
|
||||||
|
b = append(buf.Bytes(), b...)
|
||||||
|
|
||||||
|
_, err = conn.Write(b)
|
||||||
|
if err != nil {
|
||||||
|
return r, fmt.Errorf("error sending to KDC (%s): %v", conn.RemoteAddr().String(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
sh := make([]byte, 4, 4)
|
||||||
|
_, err = conn.Read(sh)
|
||||||
|
if err != nil {
|
||||||
|
return r, fmt.Errorf("error reading response size header: %v", err)
|
||||||
|
}
|
||||||
|
s := binary.BigEndian.Uint32(sh)
|
||||||
|
|
||||||
|
rb := make([]byte, s, s)
|
||||||
|
_, err = io.ReadFull(conn, rb)
|
||||||
|
if err != nil {
|
||||||
|
return r, fmt.Errorf("error reading response: %v", err)
|
||||||
|
}
|
||||||
|
if len(rb) < 1 {
|
||||||
|
return r, fmt.Errorf("no response data from KDC %s", conn.RemoteAddr().String())
|
||||||
|
}
|
||||||
|
return rb, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkForKRBError checks if the response bytes from the KDC are a KRBError.
|
||||||
|
func checkForKRBError(b []byte) ([]byte, error) {
|
||||||
|
var KRBErr messages.KRBError
|
||||||
|
if err := KRBErr.Unmarshal(b); err == nil {
|
||||||
|
return b, KRBErr
|
||||||
|
}
|
||||||
|
return b, nil
|
||||||
|
}
|
95
vendor/github.com/jcmturner/gokrb5/v8/client/passwd.go
generated
vendored
Normal file
95
vendor/github.com/jcmturner/gokrb5/v8/client/passwd.go
generated
vendored
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/jcmturner/gokrb5/v8/kadmin"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/messages"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Kpasswd server response codes.
|
||||||
|
const (
|
||||||
|
KRB5_KPASSWD_SUCCESS = 0
|
||||||
|
KRB5_KPASSWD_MALFORMED = 1
|
||||||
|
KRB5_KPASSWD_HARDERROR = 2
|
||||||
|
KRB5_KPASSWD_AUTHERROR = 3
|
||||||
|
KRB5_KPASSWD_SOFTERROR = 4
|
||||||
|
KRB5_KPASSWD_ACCESSDENIED = 5
|
||||||
|
KRB5_KPASSWD_BAD_VERSION = 6
|
||||||
|
KRB5_KPASSWD_INITIAL_FLAG_NEEDED = 7
|
||||||
|
)
|
||||||
|
|
||||||
|
// ChangePasswd changes the password of the client to the value provided.
|
||||||
|
func (cl *Client) ChangePasswd(newPasswd string) (bool, error) {
|
||||||
|
ASReq, err := messages.NewASReqForChgPasswd(cl.Credentials.Domain(), cl.Config, cl.Credentials.CName())
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
ASRep, err := cl.ASExchange(cl.Credentials.Domain(), ASReq, 0)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
msg, key, err := kadmin.ChangePasswdMsg(cl.Credentials.CName(), cl.Credentials.Domain(), newPasswd, ASRep.Ticket, ASRep.DecryptedEncPart.Key)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
r, err := cl.sendToKPasswd(msg)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
err = r.Decrypt(key)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if r.ResultCode != KRB5_KPASSWD_SUCCESS {
|
||||||
|
return false, fmt.Errorf("error response from kadmin: code: %d; result: %s; krberror: %v", r.ResultCode, r.Result, r.KRBError)
|
||||||
|
}
|
||||||
|
cl.Credentials.WithPassword(newPasswd)
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cl *Client) sendToKPasswd(msg kadmin.Request) (r kadmin.Reply, err error) {
|
||||||
|
_, kps, err := cl.Config.GetKpasswdServers(cl.Credentials.Domain(), true)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
addr := kps[1]
|
||||||
|
b, err := msg.Marshal()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(b) <= cl.Config.LibDefaults.UDPPreferenceLimit {
|
||||||
|
return cl.sendKPasswdUDP(b, addr)
|
||||||
|
}
|
||||||
|
return cl.sendKPasswdTCP(b, addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cl *Client) sendKPasswdTCP(b []byte, kadmindAddr string) (r kadmin.Reply, err error) {
|
||||||
|
tcpAddr, err := net.ResolveTCPAddr("tcp", kadmindAddr)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
conn, err := net.DialTCP("tcp", nil, tcpAddr)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rb, err := cl.sendTCP(conn, b)
|
||||||
|
err = r.Unmarshal(rb)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cl *Client) sendKPasswdUDP(b []byte, kadmindAddr string) (r kadmin.Reply, err error) {
|
||||||
|
udpAddr, err := net.ResolveUDPAddr("udp", kadmindAddr)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
conn, err := net.DialUDP("udp", nil, udpAddr)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rb, err := cl.sendUDP(conn, b)
|
||||||
|
err = r.Unmarshal(rb)
|
||||||
|
return
|
||||||
|
}
|
295
vendor/github.com/jcmturner/gokrb5/v8/client/session.go
generated
vendored
Normal file
295
vendor/github.com/jcmturner/gokrb5/v8/client/session.go
generated
vendored
Normal file
|
@ -0,0 +1,295 @@
|
||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/nametype"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/krberror"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/messages"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// sessions hold TGTs and are keyed on the realm name
|
||||||
|
type sessions struct {
|
||||||
|
Entries map[string]*session
|
||||||
|
mux sync.RWMutex
|
||||||
|
}
|
||||||
|
|
||||||
|
// destroy erases all sessions
|
||||||
|
func (s *sessions) destroy() {
|
||||||
|
s.mux.Lock()
|
||||||
|
defer s.mux.Unlock()
|
||||||
|
for k, e := range s.Entries {
|
||||||
|
e.destroy()
|
||||||
|
delete(s.Entries, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// update replaces a session with the one provided or adds it as a new one
|
||||||
|
func (s *sessions) update(sess *session) {
|
||||||
|
s.mux.Lock()
|
||||||
|
defer s.mux.Unlock()
|
||||||
|
// if a session already exists for this, cancel its auto renew.
|
||||||
|
if i, ok := s.Entries[sess.realm]; ok {
|
||||||
|
if i != sess {
|
||||||
|
// Session in the sessions cache is not the same as one provided.
|
||||||
|
// Cancel the one in the cache and add this one.
|
||||||
|
i.mux.Lock()
|
||||||
|
defer i.mux.Unlock()
|
||||||
|
i.cancel <- true
|
||||||
|
s.Entries[sess.realm] = sess
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// No session for this realm was found so just add it
|
||||||
|
s.Entries[sess.realm] = sess
|
||||||
|
}
|
||||||
|
|
||||||
|
// get returns the session for the realm specified
|
||||||
|
func (s *sessions) get(realm string) (*session, bool) {
|
||||||
|
s.mux.RLock()
|
||||||
|
defer s.mux.RUnlock()
|
||||||
|
sess, ok := s.Entries[realm]
|
||||||
|
return sess, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// session holds the TGT details for a realm
|
||||||
|
type session struct {
|
||||||
|
realm string
|
||||||
|
authTime time.Time
|
||||||
|
endTime time.Time
|
||||||
|
renewTill time.Time
|
||||||
|
tgt messages.Ticket
|
||||||
|
sessionKey types.EncryptionKey
|
||||||
|
sessionKeyExpiration time.Time
|
||||||
|
cancel chan bool
|
||||||
|
mux sync.RWMutex
|
||||||
|
}
|
||||||
|
|
||||||
|
// jsonSession is used to enable marshaling some information of a session in a JSON format
|
||||||
|
type jsonSession struct {
|
||||||
|
Realm string
|
||||||
|
AuthTime time.Time
|
||||||
|
EndTime time.Time
|
||||||
|
RenewTill time.Time
|
||||||
|
SessionKeyExpiration time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddSession adds a session for a realm with a TGT to the client's session cache.
|
||||||
|
// A goroutine is started to automatically renew the TGT before expiry.
|
||||||
|
func (cl *Client) addSession(tgt messages.Ticket, dep messages.EncKDCRepPart) {
|
||||||
|
if strings.ToLower(tgt.SName.NameString[0]) != "krbtgt" {
|
||||||
|
// Not a TGT
|
||||||
|
return
|
||||||
|
}
|
||||||
|
realm := tgt.SName.NameString[len(tgt.SName.NameString)-1]
|
||||||
|
s := &session{
|
||||||
|
realm: realm,
|
||||||
|
authTime: dep.AuthTime,
|
||||||
|
endTime: dep.EndTime,
|
||||||
|
renewTill: dep.RenewTill,
|
||||||
|
tgt: tgt,
|
||||||
|
sessionKey: dep.Key,
|
||||||
|
sessionKeyExpiration: dep.KeyExpiration,
|
||||||
|
}
|
||||||
|
cl.sessions.update(s)
|
||||||
|
cl.enableAutoSessionRenewal(s)
|
||||||
|
cl.Log("TGT session added for %s (EndTime: %v)", realm, dep.EndTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
// update overwrites the session details with those from the TGT and decrypted encPart
|
||||||
|
func (s *session) update(tgt messages.Ticket, dep messages.EncKDCRepPart) {
|
||||||
|
s.mux.Lock()
|
||||||
|
defer s.mux.Unlock()
|
||||||
|
s.authTime = dep.AuthTime
|
||||||
|
s.endTime = dep.EndTime
|
||||||
|
s.renewTill = dep.RenewTill
|
||||||
|
s.tgt = tgt
|
||||||
|
s.sessionKey = dep.Key
|
||||||
|
s.sessionKeyExpiration = dep.KeyExpiration
|
||||||
|
}
|
||||||
|
|
||||||
|
// destroy will cancel any auto renewal of the session and set the expiration times to the current time
|
||||||
|
func (s *session) destroy() {
|
||||||
|
s.mux.Lock()
|
||||||
|
defer s.mux.Unlock()
|
||||||
|
if s.cancel != nil {
|
||||||
|
s.cancel <- true
|
||||||
|
}
|
||||||
|
s.endTime = time.Now().UTC()
|
||||||
|
s.renewTill = s.endTime
|
||||||
|
s.sessionKeyExpiration = s.endTime
|
||||||
|
}
|
||||||
|
|
||||||
|
// valid informs if the TGT is still within the valid time window
|
||||||
|
func (s *session) valid() bool {
|
||||||
|
s.mux.RLock()
|
||||||
|
defer s.mux.RUnlock()
|
||||||
|
t := time.Now().UTC()
|
||||||
|
if t.Before(s.endTime) && s.authTime.Before(t) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// tgtDetails is a thread safe way to get the session's realm, TGT and session key values
|
||||||
|
func (s *session) tgtDetails() (string, messages.Ticket, types.EncryptionKey) {
|
||||||
|
s.mux.RLock()
|
||||||
|
defer s.mux.RUnlock()
|
||||||
|
return s.realm, s.tgt, s.sessionKey
|
||||||
|
}
|
||||||
|
|
||||||
|
// timeDetails is a thread safe way to get the session's validity time values
|
||||||
|
func (s *session) timeDetails() (string, time.Time, time.Time, time.Time, time.Time) {
|
||||||
|
s.mux.RLock()
|
||||||
|
defer s.mux.RUnlock()
|
||||||
|
return s.realm, s.authTime, s.endTime, s.renewTill, s.sessionKeyExpiration
|
||||||
|
}
|
||||||
|
|
||||||
|
// JSON return information about the held sessions in a JSON format.
|
||||||
|
func (s *sessions) JSON() (string, error) {
|
||||||
|
s.mux.RLock()
|
||||||
|
defer s.mux.RUnlock()
|
||||||
|
var js []jsonSession
|
||||||
|
keys := make([]string, 0, len(s.Entries))
|
||||||
|
for k := range s.Entries {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
sort.Strings(keys)
|
||||||
|
for _, k := range keys {
|
||||||
|
r, at, et, rt, kt := s.Entries[k].timeDetails()
|
||||||
|
j := jsonSession{
|
||||||
|
Realm: r,
|
||||||
|
AuthTime: at,
|
||||||
|
EndTime: et,
|
||||||
|
RenewTill: rt,
|
||||||
|
SessionKeyExpiration: kt,
|
||||||
|
}
|
||||||
|
js = append(js, j)
|
||||||
|
}
|
||||||
|
b, err := json.MarshalIndent(js, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(b), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// enableAutoSessionRenewal turns on the automatic renewal for the client's TGT session.
|
||||||
|
func (cl *Client) enableAutoSessionRenewal(s *session) {
|
||||||
|
var timer *time.Timer
|
||||||
|
s.mux.Lock()
|
||||||
|
s.cancel = make(chan bool, 1)
|
||||||
|
s.mux.Unlock()
|
||||||
|
go func(s *session) {
|
||||||
|
for {
|
||||||
|
s.mux.RLock()
|
||||||
|
w := (s.endTime.Sub(time.Now().UTC()) * 5) / 6
|
||||||
|
s.mux.RUnlock()
|
||||||
|
if w < 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
timer = time.NewTimer(w)
|
||||||
|
select {
|
||||||
|
case <-timer.C:
|
||||||
|
renewal, err := cl.refreshSession(s)
|
||||||
|
if err != nil {
|
||||||
|
cl.Log("error refreshing session: %v", err)
|
||||||
|
}
|
||||||
|
if !renewal && err == nil {
|
||||||
|
// end this goroutine as there will have been a new login and new auto renewal goroutine created.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case <-s.cancel:
|
||||||
|
// cancel has been called. Stop the timer and exit.
|
||||||
|
timer.Stop()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// renewTGT renews the client's TGT session.
|
||||||
|
func (cl *Client) renewTGT(s *session) error {
|
||||||
|
realm, tgt, skey := s.tgtDetails()
|
||||||
|
spn := types.PrincipalName{
|
||||||
|
NameType: nametype.KRB_NT_SRV_INST,
|
||||||
|
NameString: []string{"krbtgt", realm},
|
||||||
|
}
|
||||||
|
_, tgsRep, err := cl.TGSREQGenerateAndExchange(spn, cl.Credentials.Domain(), tgt, skey, true)
|
||||||
|
if err != nil {
|
||||||
|
return krberror.Errorf(err, krberror.KRBMsgError, "error renewing TGT for %s", realm)
|
||||||
|
}
|
||||||
|
s.update(tgsRep.Ticket, tgsRep.DecryptedEncPart)
|
||||||
|
cl.sessions.update(s)
|
||||||
|
cl.Log("TGT session renewed for %s (EndTime: %v)", realm, tgsRep.DecryptedEncPart.EndTime)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// refreshSession updates either through renewal or creating a new login.
|
||||||
|
// The boolean indicates if the update was a renewal.
|
||||||
|
func (cl *Client) refreshSession(s *session) (bool, error) {
|
||||||
|
s.mux.RLock()
|
||||||
|
realm := s.realm
|
||||||
|
renewTill := s.renewTill
|
||||||
|
s.mux.RUnlock()
|
||||||
|
cl.Log("refreshing TGT session for %s", realm)
|
||||||
|
if time.Now().UTC().Before(renewTill) {
|
||||||
|
err := cl.renewTGT(s)
|
||||||
|
return true, err
|
||||||
|
}
|
||||||
|
err := cl.realmLogin(realm)
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensureValidSession makes sure there is a valid session for the realm
|
||||||
|
func (cl *Client) ensureValidSession(realm string) error {
|
||||||
|
s, ok := cl.sessions.get(realm)
|
||||||
|
if ok {
|
||||||
|
s.mux.RLock()
|
||||||
|
d := s.endTime.Sub(s.authTime) / 6
|
||||||
|
if s.endTime.Sub(time.Now().UTC()) > d {
|
||||||
|
s.mux.RUnlock()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
s.mux.RUnlock()
|
||||||
|
_, err := cl.refreshSession(s)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return cl.realmLogin(realm)
|
||||||
|
}
|
||||||
|
|
||||||
|
// sessionTGTDetails is a thread safe way to get the TGT and session key values for a realm
|
||||||
|
func (cl *Client) sessionTGT(realm string) (tgt messages.Ticket, sessionKey types.EncryptionKey, err error) {
|
||||||
|
err = cl.ensureValidSession(realm)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s, ok := cl.sessions.get(realm)
|
||||||
|
if !ok {
|
||||||
|
err = fmt.Errorf("could not find TGT session for %s", realm)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, tgt, sessionKey = s.tgtDetails()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// sessionTimes provides the timing information with regards to a session for the realm specified.
|
||||||
|
func (cl *Client) sessionTimes(realm string) (authTime, endTime, renewTime, sessionExp time.Time, err error) {
|
||||||
|
s, ok := cl.sessions.get(realm)
|
||||||
|
if !ok {
|
||||||
|
err = fmt.Errorf("could not find TGT session for %s", realm)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, authTime, endTime, renewTime, sessionExp = s.timeDetails()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// spnRealm resolves the realm name of a service principal name
|
||||||
|
func (cl *Client) spnRealm(spn types.PrincipalName) string {
|
||||||
|
return cl.Config.ResolveRealm(spn.NameString[len(spn.NameString)-1])
|
||||||
|
}
|
93
vendor/github.com/jcmturner/gokrb5/v8/client/settings.go
generated
vendored
Normal file
93
vendor/github.com/jcmturner/gokrb5/v8/client/settings.go
generated
vendored
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Settings holds optional client settings.
|
||||||
|
type Settings struct {
|
||||||
|
disablePAFXFast bool
|
||||||
|
assumePreAuthentication bool
|
||||||
|
preAuthEType int32
|
||||||
|
logger *log.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
// jsonSettings is used when marshaling the Settings details to JSON format.
|
||||||
|
type jsonSettings struct {
|
||||||
|
DisablePAFXFast bool
|
||||||
|
AssumePreAuthentication bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSettings creates a new client settings struct.
|
||||||
|
func NewSettings(settings ...func(*Settings)) *Settings {
|
||||||
|
s := new(Settings)
|
||||||
|
for _, set := range settings {
|
||||||
|
set(s)
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// DisablePAFXFAST used to configure the client to not use PA_FX_FAST.
|
||||||
|
//
|
||||||
|
// s := NewSettings(DisablePAFXFAST(true))
|
||||||
|
func DisablePAFXFAST(b bool) func(*Settings) {
|
||||||
|
return func(s *Settings) {
|
||||||
|
s.disablePAFXFast = b
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DisablePAFXFAST indicates is the client should disable the use of PA_FX_FAST.
|
||||||
|
func (s *Settings) DisablePAFXFAST() bool {
|
||||||
|
return s.disablePAFXFast
|
||||||
|
}
|
||||||
|
|
||||||
|
// AssumePreAuthentication used to configure the client to assume pre-authentication is required.
|
||||||
|
//
|
||||||
|
// s := NewSettings(AssumePreAuthentication(true))
|
||||||
|
func AssumePreAuthentication(b bool) func(*Settings) {
|
||||||
|
return func(s *Settings) {
|
||||||
|
s.assumePreAuthentication = b
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AssumePreAuthentication indicates if the client should proactively assume using pre-authentication.
|
||||||
|
func (s *Settings) AssumePreAuthentication() bool {
|
||||||
|
return s.assumePreAuthentication
|
||||||
|
}
|
||||||
|
|
||||||
|
// Logger used to configure client with a logger.
|
||||||
|
//
|
||||||
|
// s := NewSettings(kt, Logger(l))
|
||||||
|
func Logger(l *log.Logger) func(*Settings) {
|
||||||
|
return func(s *Settings) {
|
||||||
|
s.logger = l
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Logger returns the client logger instance.
|
||||||
|
func (s *Settings) Logger() *log.Logger {
|
||||||
|
return s.logger
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log will write to the service's logger if it is configured.
|
||||||
|
func (cl *Client) Log(format string, v ...interface{}) {
|
||||||
|
if cl.settings.Logger() != nil {
|
||||||
|
cl.settings.Logger().Output(2, fmt.Sprintf(format, v...))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// JSON returns a JSON representation of the settings.
|
||||||
|
func (s *Settings) JSON() (string, error) {
|
||||||
|
js := jsonSettings{
|
||||||
|
DisablePAFXFast: s.disablePAFXFast,
|
||||||
|
AssumePreAuthentication: s.assumePreAuthentication,
|
||||||
|
}
|
||||||
|
b, err := json.MarshalIndent(js, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(b), nil
|
||||||
|
|
||||||
|
}
|
30
vendor/github.com/jcmturner/gokrb5/v8/config/error.go
generated
vendored
Normal file
30
vendor/github.com/jcmturner/gokrb5/v8/config/error.go
generated
vendored
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
package config
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
// UnsupportedDirective error.
|
||||||
|
type UnsupportedDirective struct {
|
||||||
|
text string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error implements the error interface for unsupported directives.
|
||||||
|
func (e UnsupportedDirective) Error() string {
|
||||||
|
return e.text
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invalid config error.
|
||||||
|
type Invalid struct {
|
||||||
|
text string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error implements the error interface for invalid config error.
|
||||||
|
func (e Invalid) Error() string {
|
||||||
|
return e.text
|
||||||
|
}
|
||||||
|
|
||||||
|
// InvalidErrorf creates a new Invalid error.
|
||||||
|
func InvalidErrorf(format string, a ...interface{}) Invalid {
|
||||||
|
return Invalid{
|
||||||
|
text: fmt.Sprintf("invalid krb5 config "+format, a...),
|
||||||
|
}
|
||||||
|
}
|
141
vendor/github.com/jcmturner/gokrb5/v8/config/hosts.go
generated
vendored
Normal file
141
vendor/github.com/jcmturner/gokrb5/v8/config/hosts.go
generated
vendored
Normal file
|
@ -0,0 +1,141 @@
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
|
"net"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/jcmturner/dnsutils/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetKDCs returns the count of KDCs available and a map of KDC host names keyed on preference order.
|
||||||
|
func (c *Config) GetKDCs(realm string, tcp bool) (int, map[int]string, error) {
|
||||||
|
if realm == "" {
|
||||||
|
realm = c.LibDefaults.DefaultRealm
|
||||||
|
}
|
||||||
|
kdcs := make(map[int]string)
|
||||||
|
var count int
|
||||||
|
|
||||||
|
// Get the KDCs from the krb5.conf.
|
||||||
|
var ks []string
|
||||||
|
for _, r := range c.Realms {
|
||||||
|
if r.Realm != realm {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ks = r.KDC
|
||||||
|
}
|
||||||
|
count = len(ks)
|
||||||
|
|
||||||
|
if count > 0 {
|
||||||
|
// Order the kdcs randomly for preference.
|
||||||
|
kdcs = randServOrder(ks)
|
||||||
|
return count, kdcs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if !c.LibDefaults.DNSLookupKDC {
|
||||||
|
return count, kdcs, fmt.Errorf("no KDCs defined in configuration for realm %s", realm)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use DNS to resolve kerberos SRV records.
|
||||||
|
proto := "udp"
|
||||||
|
if tcp {
|
||||||
|
proto = "tcp"
|
||||||
|
}
|
||||||
|
index, addrs, err := dnsutils.OrderedSRV("kerberos", proto, realm)
|
||||||
|
if err != nil {
|
||||||
|
return count, kdcs, err
|
||||||
|
}
|
||||||
|
if len(addrs) < 1 {
|
||||||
|
return count, kdcs, fmt.Errorf("no KDC SRV records found for realm %s", realm)
|
||||||
|
}
|
||||||
|
count = index
|
||||||
|
for k, v := range addrs {
|
||||||
|
kdcs[k] = strings.TrimRight(v.Target, ".") + ":" + strconv.Itoa(int(v.Port))
|
||||||
|
}
|
||||||
|
return count, kdcs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetKpasswdServers returns the count of kpasswd servers available and a map of kpasswd host names keyed on preference order.
|
||||||
|
// https://web.mit.edu/kerberos/krb5-latest/doc/admin/conf_files/krb5_conf.html#realms - see kpasswd_server section
|
||||||
|
func (c *Config) GetKpasswdServers(realm string, tcp bool) (int, map[int]string, error) {
|
||||||
|
kdcs := make(map[int]string)
|
||||||
|
var count int
|
||||||
|
|
||||||
|
// Use DNS to resolve kerberos SRV records if configured to do so in krb5.conf.
|
||||||
|
if c.LibDefaults.DNSLookupKDC {
|
||||||
|
proto := "udp"
|
||||||
|
if tcp {
|
||||||
|
proto = "tcp"
|
||||||
|
}
|
||||||
|
c, addrs, err := dnsutils.OrderedSRV("kpasswd", proto, realm)
|
||||||
|
if err != nil {
|
||||||
|
return count, kdcs, err
|
||||||
|
}
|
||||||
|
if c < 1 {
|
||||||
|
c, addrs, err = dnsutils.OrderedSRV("kerberos-adm", proto, realm)
|
||||||
|
if err != nil {
|
||||||
|
return count, kdcs, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(addrs) < 1 {
|
||||||
|
return count, kdcs, fmt.Errorf("no kpasswd or kadmin SRV records found for realm %s", realm)
|
||||||
|
}
|
||||||
|
count = c
|
||||||
|
for k, v := range addrs {
|
||||||
|
kdcs[k] = strings.TrimRight(v.Target, ".") + ":" + strconv.Itoa(int(v.Port))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Get the KDCs from the krb5.conf an order them randomly for preference.
|
||||||
|
var ks []string
|
||||||
|
var ka []string
|
||||||
|
for _, r := range c.Realms {
|
||||||
|
if r.Realm == realm {
|
||||||
|
ks = r.KPasswdServer
|
||||||
|
ka = r.AdminServer
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(ks) < 1 {
|
||||||
|
for _, k := range ka {
|
||||||
|
h, _, err := net.SplitHostPort(k)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ks = append(ks, h+":464")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
count = len(ks)
|
||||||
|
if count < 1 {
|
||||||
|
return count, kdcs, fmt.Errorf("no kpasswd or kadmin defined in configuration for realm %s", realm)
|
||||||
|
}
|
||||||
|
kdcs = randServOrder(ks)
|
||||||
|
}
|
||||||
|
return count, kdcs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func randServOrder(ks []string) map[int]string {
|
||||||
|
kdcs := make(map[int]string)
|
||||||
|
count := len(ks)
|
||||||
|
i := 1
|
||||||
|
if count > 1 {
|
||||||
|
l := len(ks)
|
||||||
|
for l > 0 {
|
||||||
|
ri := rand.Intn(l)
|
||||||
|
kdcs[i] = ks[ri]
|
||||||
|
if l > 1 {
|
||||||
|
// Remove the entry from the source slice by swapping with the last entry and truncating
|
||||||
|
ks[len(ks)-1], ks[ri] = ks[ri], ks[len(ks)-1]
|
||||||
|
ks = ks[:len(ks)-1]
|
||||||
|
l = len(ks)
|
||||||
|
} else {
|
||||||
|
l = 0
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
kdcs[i] = ks[0]
|
||||||
|
}
|
||||||
|
return kdcs
|
||||||
|
}
|
728
vendor/github.com/jcmturner/gokrb5/v8/config/krb5conf.go
generated
vendored
Normal file
728
vendor/github.com/jcmturner/gokrb5/v8/config/krb5conf.go
generated
vendored
Normal file
|
@ -0,0 +1,728 @@
|
||||||
|
// Package config implements KRB5 client and service configuration as described at https://web.mit.edu/kerberos/krb5-latest/doc/admin/conf_files/krb5_conf.html
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"os/user"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/jcmturner/gofork/encoding/asn1"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/etypeID"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Config represents the KRB5 configuration.
|
||||||
|
type Config struct {
|
||||||
|
LibDefaults LibDefaults
|
||||||
|
Realms []Realm
|
||||||
|
DomainRealm DomainRealm
|
||||||
|
//CaPaths
|
||||||
|
//AppDefaults
|
||||||
|
//Plugins
|
||||||
|
}
|
||||||
|
|
||||||
|
// WeakETypeList is a list of encryption types that have been deemed weak.
|
||||||
|
const WeakETypeList = "des-cbc-crc des-cbc-md4 des-cbc-md5 des-cbc-raw des3-cbc-raw des-hmac-sha1 arcfour-hmac-exp rc4-hmac-exp arcfour-hmac-md5-exp des"
|
||||||
|
|
||||||
|
// New creates a new config struct instance.
|
||||||
|
func New() *Config {
|
||||||
|
d := make(DomainRealm)
|
||||||
|
return &Config{
|
||||||
|
LibDefaults: newLibDefaults(),
|
||||||
|
DomainRealm: d,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LibDefaults represents the [libdefaults] section of the configuration.
|
||||||
|
type LibDefaults struct {
|
||||||
|
AllowWeakCrypto bool //default false
|
||||||
|
// ap_req_checksum_type int //unlikely to support this
|
||||||
|
Canonicalize bool //default false
|
||||||
|
CCacheType int //default is 4. unlikely to implement older
|
||||||
|
Clockskew time.Duration //max allowed skew in seconds, default 300
|
||||||
|
//Default_ccache_name string // default /tmp/krb5cc_%{uid} //Not implementing as will hold in memory
|
||||||
|
DefaultClientKeytabName string //default /usr/local/var/krb5/user/%{euid}/client.keytab
|
||||||
|
DefaultKeytabName string //default /etc/krb5.keytab
|
||||||
|
DefaultRealm string
|
||||||
|
DefaultTGSEnctypes []string //default aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96 des3-cbc-sha1 arcfour-hmac-md5 camellia256-cts-cmac camellia128-cts-cmac des-cbc-crc des-cbc-md5 des-cbc-md4
|
||||||
|
DefaultTktEnctypes []string //default aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96 des3-cbc-sha1 arcfour-hmac-md5 camellia256-cts-cmac camellia128-cts-cmac des-cbc-crc des-cbc-md5 des-cbc-md4
|
||||||
|
DefaultTGSEnctypeIDs []int32 //default aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96 des3-cbc-sha1 arcfour-hmac-md5 camellia256-cts-cmac camellia128-cts-cmac des-cbc-crc des-cbc-md5 des-cbc-md4
|
||||||
|
DefaultTktEnctypeIDs []int32 //default aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96 des3-cbc-sha1 arcfour-hmac-md5 camellia256-cts-cmac camellia128-cts-cmac des-cbc-crc des-cbc-md5 des-cbc-md4
|
||||||
|
DNSCanonicalizeHostname bool //default true
|
||||||
|
DNSLookupKDC bool //default false
|
||||||
|
DNSLookupRealm bool
|
||||||
|
ExtraAddresses []net.IP //Not implementing yet
|
||||||
|
Forwardable bool //default false
|
||||||
|
IgnoreAcceptorHostname bool //default false
|
||||||
|
K5LoginAuthoritative bool //default false
|
||||||
|
K5LoginDirectory string //default user's home directory. Must be owned by the user or root
|
||||||
|
KDCDefaultOptions asn1.BitString //default 0x00000010 (KDC_OPT_RENEWABLE_OK)
|
||||||
|
KDCTimeSync int //default 1
|
||||||
|
//kdc_req_checksum_type int //unlikely to implement as for very old KDCs
|
||||||
|
NoAddresses bool //default true
|
||||||
|
PermittedEnctypes []string //default aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96 des3-cbc-sha1 arcfour-hmac-md5 camellia256-cts-cmac camellia128-cts-cmac des-cbc-crc des-cbc-md5 des-cbc-md4
|
||||||
|
PermittedEnctypeIDs []int32
|
||||||
|
//plugin_base_dir string //not supporting plugins
|
||||||
|
PreferredPreauthTypes []int //default “17, 16, 15, 14”, which forces libkrb5 to attempt to use PKINIT if it is supported
|
||||||
|
Proxiable bool //default false
|
||||||
|
RDNS bool //default true
|
||||||
|
RealmTryDomains int //default -1
|
||||||
|
RenewLifetime time.Duration //default 0
|
||||||
|
SafeChecksumType int //default 8
|
||||||
|
TicketLifetime time.Duration //default 1 day
|
||||||
|
UDPPreferenceLimit int // 1 means to always use tcp. MIT krb5 has a default value of 1465, and it prevents user setting more than 32700.
|
||||||
|
VerifyAPReqNofail bool //default false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new LibDefaults struct.
|
||||||
|
func newLibDefaults() LibDefaults {
|
||||||
|
uid := "0"
|
||||||
|
var hdir string
|
||||||
|
usr, _ := user.Current()
|
||||||
|
if usr != nil {
|
||||||
|
uid = usr.Uid
|
||||||
|
hdir = usr.HomeDir
|
||||||
|
}
|
||||||
|
opts := asn1.BitString{}
|
||||||
|
opts.Bytes, _ = hex.DecodeString("00000010")
|
||||||
|
opts.BitLength = len(opts.Bytes) * 8
|
||||||
|
return LibDefaults{
|
||||||
|
CCacheType: 4,
|
||||||
|
Clockskew: time.Duration(300) * time.Second,
|
||||||
|
DefaultClientKeytabName: fmt.Sprintf("/usr/local/var/krb5/user/%s/client.keytab", uid),
|
||||||
|
DefaultKeytabName: "/etc/krb5.keytab",
|
||||||
|
DefaultTGSEnctypes: []string{"aes256-cts-hmac-sha1-96", "aes128-cts-hmac-sha1-96", "des3-cbc-sha1", "arcfour-hmac-md5", "camellia256-cts-cmac", "camellia128-cts-cmac", "des-cbc-crc", "des-cbc-md5", "des-cbc-md4"},
|
||||||
|
DefaultTktEnctypes: []string{"aes256-cts-hmac-sha1-96", "aes128-cts-hmac-sha1-96", "des3-cbc-sha1", "arcfour-hmac-md5", "camellia256-cts-cmac", "camellia128-cts-cmac", "des-cbc-crc", "des-cbc-md5", "des-cbc-md4"},
|
||||||
|
DNSCanonicalizeHostname: true,
|
||||||
|
K5LoginDirectory: hdir,
|
||||||
|
KDCDefaultOptions: opts,
|
||||||
|
KDCTimeSync: 1,
|
||||||
|
NoAddresses: true,
|
||||||
|
PermittedEnctypes: []string{"aes256-cts-hmac-sha1-96", "aes128-cts-hmac-sha1-96", "des3-cbc-sha1", "arcfour-hmac-md5", "camellia256-cts-cmac", "camellia128-cts-cmac", "des-cbc-crc", "des-cbc-md5", "des-cbc-md4"},
|
||||||
|
RDNS: true,
|
||||||
|
RealmTryDomains: -1,
|
||||||
|
SafeChecksumType: 8,
|
||||||
|
TicketLifetime: time.Duration(24) * time.Hour,
|
||||||
|
UDPPreferenceLimit: 1465,
|
||||||
|
PreferredPreauthTypes: []int{17, 16, 15, 14},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the lines of the [libdefaults] section of the configuration into the LibDefaults struct.
|
||||||
|
func (l *LibDefaults) parseLines(lines []string) error {
|
||||||
|
for _, line := range lines {
|
||||||
|
//Remove comments after the values
|
||||||
|
if idx := strings.IndexAny(line, "#;"); idx != -1 {
|
||||||
|
line = line[:idx]
|
||||||
|
}
|
||||||
|
line = strings.TrimSpace(line)
|
||||||
|
if line == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !strings.Contains(line, "=") {
|
||||||
|
return InvalidErrorf("libdefaults section line (%s)", line)
|
||||||
|
}
|
||||||
|
|
||||||
|
p := strings.Split(line, "=")
|
||||||
|
key := strings.TrimSpace(strings.ToLower(p[0]))
|
||||||
|
switch key {
|
||||||
|
case "allow_weak_crypto":
|
||||||
|
v, err := parseBoolean(p[1])
|
||||||
|
if err != nil {
|
||||||
|
return InvalidErrorf("libdefaults section line (%s): %v", line, err)
|
||||||
|
}
|
||||||
|
l.AllowWeakCrypto = v
|
||||||
|
case "canonicalize":
|
||||||
|
v, err := parseBoolean(p[1])
|
||||||
|
if err != nil {
|
||||||
|
return InvalidErrorf("libdefaults section line (%s): %v", line, err)
|
||||||
|
}
|
||||||
|
l.Canonicalize = v
|
||||||
|
case "ccache_type":
|
||||||
|
p[1] = strings.TrimSpace(p[1])
|
||||||
|
v, err := strconv.ParseUint(p[1], 10, 32)
|
||||||
|
if err != nil || v < 0 || v > 4 {
|
||||||
|
return InvalidErrorf("libdefaults section line (%s)", line)
|
||||||
|
}
|
||||||
|
l.CCacheType = int(v)
|
||||||
|
case "clockskew":
|
||||||
|
d, err := parseDuration(p[1])
|
||||||
|
if err != nil {
|
||||||
|
return InvalidErrorf("libdefaults section line (%s): %v", line, err)
|
||||||
|
}
|
||||||
|
l.Clockskew = d
|
||||||
|
case "default_client_keytab_name":
|
||||||
|
l.DefaultClientKeytabName = strings.TrimSpace(p[1])
|
||||||
|
case "default_keytab_name":
|
||||||
|
l.DefaultKeytabName = strings.TrimSpace(p[1])
|
||||||
|
case "default_realm":
|
||||||
|
l.DefaultRealm = strings.TrimSpace(p[1])
|
||||||
|
case "default_tgs_enctypes":
|
||||||
|
l.DefaultTGSEnctypes = strings.Fields(p[1])
|
||||||
|
case "default_tkt_enctypes":
|
||||||
|
l.DefaultTktEnctypes = strings.Fields(p[1])
|
||||||
|
case "dns_canonicalize_hostname":
|
||||||
|
v, err := parseBoolean(p[1])
|
||||||
|
if err != nil {
|
||||||
|
return InvalidErrorf("libdefaults section line (%s): %v", line, err)
|
||||||
|
}
|
||||||
|
l.DNSCanonicalizeHostname = v
|
||||||
|
case "dns_lookup_kdc":
|
||||||
|
v, err := parseBoolean(p[1])
|
||||||
|
if err != nil {
|
||||||
|
return InvalidErrorf("libdefaults section line (%s): %v", line, err)
|
||||||
|
}
|
||||||
|
l.DNSLookupKDC = v
|
||||||
|
case "dns_lookup_realm":
|
||||||
|
v, err := parseBoolean(p[1])
|
||||||
|
if err != nil {
|
||||||
|
return InvalidErrorf("libdefaults section line (%s): %v", line, err)
|
||||||
|
}
|
||||||
|
l.DNSLookupRealm = v
|
||||||
|
case "extra_addresses":
|
||||||
|
ipStr := strings.TrimSpace(p[1])
|
||||||
|
for _, ip := range strings.Split(ipStr, ",") {
|
||||||
|
if eip := net.ParseIP(ip); eip != nil {
|
||||||
|
l.ExtraAddresses = append(l.ExtraAddresses, eip)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case "forwardable":
|
||||||
|
v, err := parseBoolean(p[1])
|
||||||
|
if err != nil {
|
||||||
|
return InvalidErrorf("libdefaults section line (%s): %v", line, err)
|
||||||
|
}
|
||||||
|
l.Forwardable = v
|
||||||
|
case "ignore_acceptor_hostname":
|
||||||
|
v, err := parseBoolean(p[1])
|
||||||
|
if err != nil {
|
||||||
|
return InvalidErrorf("libdefaults section line (%s): %v", line, err)
|
||||||
|
}
|
||||||
|
l.IgnoreAcceptorHostname = v
|
||||||
|
case "k5login_authoritative":
|
||||||
|
v, err := parseBoolean(p[1])
|
||||||
|
if err != nil {
|
||||||
|
return InvalidErrorf("libdefaults section line (%s): %v", line, err)
|
||||||
|
}
|
||||||
|
l.K5LoginAuthoritative = v
|
||||||
|
case "k5login_directory":
|
||||||
|
l.K5LoginDirectory = strings.TrimSpace(p[1])
|
||||||
|
case "kdc_default_options":
|
||||||
|
v := strings.TrimSpace(p[1])
|
||||||
|
v = strings.Replace(v, "0x", "", -1)
|
||||||
|
b, err := hex.DecodeString(v)
|
||||||
|
if err != nil {
|
||||||
|
return InvalidErrorf("libdefaults section line (%s): %v", line, err)
|
||||||
|
}
|
||||||
|
l.KDCDefaultOptions.Bytes = b
|
||||||
|
l.KDCDefaultOptions.BitLength = len(b) * 8
|
||||||
|
case "kdc_timesync":
|
||||||
|
p[1] = strings.TrimSpace(p[1])
|
||||||
|
v, err := strconv.ParseInt(p[1], 10, 32)
|
||||||
|
if err != nil || v < 0 {
|
||||||
|
return InvalidErrorf("libdefaults section line (%s)", line)
|
||||||
|
}
|
||||||
|
l.KDCTimeSync = int(v)
|
||||||
|
case "noaddresses":
|
||||||
|
v, err := parseBoolean(p[1])
|
||||||
|
if err != nil {
|
||||||
|
return InvalidErrorf("libdefaults section line (%s): %v", line, err)
|
||||||
|
}
|
||||||
|
l.NoAddresses = v
|
||||||
|
case "permitted_enctypes":
|
||||||
|
l.PermittedEnctypes = strings.Fields(p[1])
|
||||||
|
case "preferred_preauth_types":
|
||||||
|
p[1] = strings.TrimSpace(p[1])
|
||||||
|
t := strings.Split(p[1], ",")
|
||||||
|
var v []int
|
||||||
|
for _, s := range t {
|
||||||
|
i, err := strconv.ParseInt(s, 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
return InvalidErrorf("libdefaults section line (%s): %v", line, err)
|
||||||
|
}
|
||||||
|
v = append(v, int(i))
|
||||||
|
}
|
||||||
|
l.PreferredPreauthTypes = v
|
||||||
|
case "proxiable":
|
||||||
|
v, err := parseBoolean(p[1])
|
||||||
|
if err != nil {
|
||||||
|
return InvalidErrorf("libdefaults section line (%s): %v", line, err)
|
||||||
|
}
|
||||||
|
l.Proxiable = v
|
||||||
|
case "rdns":
|
||||||
|
v, err := parseBoolean(p[1])
|
||||||
|
if err != nil {
|
||||||
|
return InvalidErrorf("libdefaults section line (%s): %v", line, err)
|
||||||
|
}
|
||||||
|
l.RDNS = v
|
||||||
|
case "realm_try_domains":
|
||||||
|
p[1] = strings.TrimSpace(p[1])
|
||||||
|
v, err := strconv.ParseInt(p[1], 10, 32)
|
||||||
|
if err != nil || v < -1 {
|
||||||
|
return InvalidErrorf("libdefaults section line (%s)", line)
|
||||||
|
}
|
||||||
|
l.RealmTryDomains = int(v)
|
||||||
|
case "renew_lifetime":
|
||||||
|
d, err := parseDuration(p[1])
|
||||||
|
if err != nil {
|
||||||
|
return InvalidErrorf("libdefaults section line (%s): %v", line, err)
|
||||||
|
}
|
||||||
|
l.RenewLifetime = d
|
||||||
|
case "safe_checksum_type":
|
||||||
|
p[1] = strings.TrimSpace(p[1])
|
||||||
|
v, err := strconv.ParseInt(p[1], 10, 32)
|
||||||
|
if err != nil || v < 0 {
|
||||||
|
return InvalidErrorf("libdefaults section line (%s)", line)
|
||||||
|
}
|
||||||
|
l.SafeChecksumType = int(v)
|
||||||
|
case "ticket_lifetime":
|
||||||
|
d, err := parseDuration(p[1])
|
||||||
|
if err != nil {
|
||||||
|
return InvalidErrorf("libdefaults section line (%s): %v", line, err)
|
||||||
|
}
|
||||||
|
l.TicketLifetime = d
|
||||||
|
case "udp_preference_limit":
|
||||||
|
p[1] = strings.TrimSpace(p[1])
|
||||||
|
v, err := strconv.ParseUint(p[1], 10, 32)
|
||||||
|
if err != nil || v > 32700 {
|
||||||
|
return InvalidErrorf("libdefaults section line (%s)", line)
|
||||||
|
}
|
||||||
|
l.UDPPreferenceLimit = int(v)
|
||||||
|
case "verify_ap_req_nofail":
|
||||||
|
v, err := parseBoolean(p[1])
|
||||||
|
if err != nil {
|
||||||
|
return InvalidErrorf("libdefaults section line (%s): %v", line, err)
|
||||||
|
}
|
||||||
|
l.VerifyAPReqNofail = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
l.DefaultTGSEnctypeIDs = parseETypes(l.DefaultTGSEnctypes, l.AllowWeakCrypto)
|
||||||
|
l.DefaultTktEnctypeIDs = parseETypes(l.DefaultTktEnctypes, l.AllowWeakCrypto)
|
||||||
|
l.PermittedEnctypeIDs = parseETypes(l.PermittedEnctypes, l.AllowWeakCrypto)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Realm represents an entry in the [realms] section of the configuration.
|
||||||
|
type Realm struct {
|
||||||
|
Realm string
|
||||||
|
AdminServer []string
|
||||||
|
//auth_to_local //Not implementing for now
|
||||||
|
//auth_to_local_names //Not implementing for now
|
||||||
|
DefaultDomain string
|
||||||
|
KDC []string
|
||||||
|
KPasswdServer []string //default admin_server:464
|
||||||
|
MasterKDC []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the lines of a [realms] entry into the Realm struct.
|
||||||
|
func (r *Realm) parseLines(name string, lines []string) (err error) {
|
||||||
|
r.Realm = name
|
||||||
|
var adminServerFinal bool
|
||||||
|
var KDCFinal bool
|
||||||
|
var kpasswdServerFinal bool
|
||||||
|
var masterKDCFinal bool
|
||||||
|
var ignore bool
|
||||||
|
var c int // counts the depth of blocks within brackets { }
|
||||||
|
for _, line := range lines {
|
||||||
|
if ignore && c > 0 && !strings.Contains(line, "{") && !strings.Contains(line, "}") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
//Remove comments after the values
|
||||||
|
if idx := strings.IndexAny(line, "#;"); idx != -1 {
|
||||||
|
line = line[:idx]
|
||||||
|
}
|
||||||
|
line = strings.TrimSpace(line)
|
||||||
|
if line == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !strings.Contains(line, "=") && !strings.Contains(line, "}") {
|
||||||
|
return InvalidErrorf("realms section line (%s)", line)
|
||||||
|
}
|
||||||
|
if strings.Contains(line, "v4_") {
|
||||||
|
ignore = true
|
||||||
|
err = UnsupportedDirective{"v4 configurations are not supported"}
|
||||||
|
}
|
||||||
|
if strings.Contains(line, "{") {
|
||||||
|
c++
|
||||||
|
if ignore {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if strings.Contains(line, "}") {
|
||||||
|
c--
|
||||||
|
if c < 0 {
|
||||||
|
return InvalidErrorf("unpaired curly brackets")
|
||||||
|
}
|
||||||
|
if ignore {
|
||||||
|
if c < 1 {
|
||||||
|
c = 0
|
||||||
|
ignore = false
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p := strings.Split(line, "=")
|
||||||
|
key := strings.TrimSpace(strings.ToLower(p[0]))
|
||||||
|
v := strings.TrimSpace(p[1])
|
||||||
|
switch key {
|
||||||
|
case "admin_server":
|
||||||
|
appendUntilFinal(&r.AdminServer, v, &adminServerFinal)
|
||||||
|
case "default_domain":
|
||||||
|
r.DefaultDomain = v
|
||||||
|
case "kdc":
|
||||||
|
if !strings.Contains(v, ":") {
|
||||||
|
// No port number specified default to 88
|
||||||
|
if strings.HasSuffix(v, `*`) {
|
||||||
|
v = strings.TrimSpace(strings.TrimSuffix(v, `*`)) + ":88*"
|
||||||
|
} else {
|
||||||
|
v = strings.TrimSpace(v) + ":88"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
appendUntilFinal(&r.KDC, v, &KDCFinal)
|
||||||
|
case "kpasswd_server":
|
||||||
|
appendUntilFinal(&r.KPasswdServer, v, &kpasswdServerFinal)
|
||||||
|
case "master_kdc":
|
||||||
|
appendUntilFinal(&r.MasterKDC, v, &masterKDCFinal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//default for Kpasswd_server = admin_server:464
|
||||||
|
if len(r.KPasswdServer) < 1 {
|
||||||
|
for _, a := range r.AdminServer {
|
||||||
|
s := strings.Split(a, ":")
|
||||||
|
r.KPasswdServer = append(r.KPasswdServer, s[0]+":464")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the lines of the [realms] section of the configuration into an slice of Realm structs.
|
||||||
|
func parseRealms(lines []string) (realms []Realm, err error) {
|
||||||
|
var name string
|
||||||
|
var start int
|
||||||
|
var c int
|
||||||
|
for i, l := range lines {
|
||||||
|
//Remove comments after the values
|
||||||
|
if idx := strings.IndexAny(l, "#;"); idx != -1 {
|
||||||
|
l = l[:idx]
|
||||||
|
}
|
||||||
|
l = strings.TrimSpace(l)
|
||||||
|
if l == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
//if strings.Contains(l, "v4_") {
|
||||||
|
// return nil, errors.New("v4 configurations are not supported in Realms section")
|
||||||
|
//}
|
||||||
|
if strings.Contains(l, "{") {
|
||||||
|
c++
|
||||||
|
if !strings.Contains(l, "=") {
|
||||||
|
return nil, fmt.Errorf("realm configuration line invalid: %s", l)
|
||||||
|
}
|
||||||
|
if c == 1 {
|
||||||
|
start = i
|
||||||
|
p := strings.Split(l, "=")
|
||||||
|
name = strings.TrimSpace(p[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if strings.Contains(l, "}") {
|
||||||
|
if c < 1 {
|
||||||
|
// but not started a block!!!
|
||||||
|
return nil, errors.New("invalid Realms section in configuration")
|
||||||
|
}
|
||||||
|
c--
|
||||||
|
if c == 0 {
|
||||||
|
var r Realm
|
||||||
|
e := r.parseLines(name, lines[start+1:i])
|
||||||
|
if e != nil {
|
||||||
|
if _, ok := e.(UnsupportedDirective); !ok {
|
||||||
|
err = e
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = e
|
||||||
|
}
|
||||||
|
realms = append(realms, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DomainRealm maps the domains to realms representing the [domain_realm] section of the configuration.
|
||||||
|
type DomainRealm map[string]string
|
||||||
|
|
||||||
|
// Parse the lines of the [domain_realm] section of the configuration and add to the mapping.
|
||||||
|
func (d *DomainRealm) parseLines(lines []string) error {
|
||||||
|
for _, line := range lines {
|
||||||
|
//Remove comments after the values
|
||||||
|
if idx := strings.IndexAny(line, "#;"); idx != -1 {
|
||||||
|
line = line[:idx]
|
||||||
|
}
|
||||||
|
if strings.TrimSpace(line) == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !strings.Contains(line, "=") {
|
||||||
|
return InvalidErrorf("realm line (%s)", line)
|
||||||
|
}
|
||||||
|
p := strings.Split(line, "=")
|
||||||
|
domain := strings.TrimSpace(strings.ToLower(p[0]))
|
||||||
|
realm := strings.TrimSpace(p[1])
|
||||||
|
d.addMapping(domain, realm)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a domain to realm mapping.
|
||||||
|
func (d *DomainRealm) addMapping(domain, realm string) {
|
||||||
|
(*d)[domain] = realm
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete a domain to realm mapping.
|
||||||
|
func (d *DomainRealm) deleteMapping(domain, realm string) {
|
||||||
|
delete(*d, domain)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResolveRealm resolves the kerberos realm for the specified domain name from the domain to realm mapping.
|
||||||
|
// The most specific mapping is returned.
|
||||||
|
func (c *Config) ResolveRealm(domainName string) string {
|
||||||
|
domainName = strings.TrimSuffix(domainName, ".")
|
||||||
|
|
||||||
|
// Try to match the entire hostname first
|
||||||
|
if r, ok := c.DomainRealm[domainName]; ok {
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to match all DNS domain parts
|
||||||
|
periods := strings.Count(domainName, ".") + 1
|
||||||
|
for i := 2; i <= periods; i++ {
|
||||||
|
z := strings.SplitN(domainName, ".", i)
|
||||||
|
if r, ok := c.DomainRealm["."+z[len(z)-1]]; ok {
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c.LibDefaults.DefaultRealm
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load the KRB5 configuration from the specified file path.
|
||||||
|
func Load(cfgPath string) (*Config, error) {
|
||||||
|
fh, err := os.Open(cfgPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("configuration file could not be opened: " + cfgPath + " " + err.Error())
|
||||||
|
}
|
||||||
|
defer fh.Close()
|
||||||
|
scanner := bufio.NewScanner(fh)
|
||||||
|
return NewFromScanner(scanner)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFromString creates a new Config struct from a string.
|
||||||
|
func NewFromString(s string) (*Config, error) {
|
||||||
|
reader := strings.NewReader(s)
|
||||||
|
return NewFromReader(reader)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFromReader creates a new Config struct from an io.Reader.
|
||||||
|
func NewFromReader(r io.Reader) (*Config, error) {
|
||||||
|
scanner := bufio.NewScanner(r)
|
||||||
|
return NewFromScanner(scanner)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFromScanner creates a new Config struct from a bufio.Scanner.
|
||||||
|
func NewFromScanner(scanner *bufio.Scanner) (*Config, error) {
|
||||||
|
c := New()
|
||||||
|
var e error
|
||||||
|
sections := make(map[int]string)
|
||||||
|
var sectionLineNum []int
|
||||||
|
var lines []string
|
||||||
|
for scanner.Scan() {
|
||||||
|
// Skip comments and blank lines
|
||||||
|
if matched, _ := regexp.MatchString(`^\s*(#|;|\n)`, scanner.Text()); matched {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if matched, _ := regexp.MatchString(`^\s*\[libdefaults\]\s*`, scanner.Text()); matched {
|
||||||
|
sections[len(lines)] = "libdefaults"
|
||||||
|
sectionLineNum = append(sectionLineNum, len(lines))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if matched, _ := regexp.MatchString(`^\s*\[realms\]\s*`, scanner.Text()); matched {
|
||||||
|
sections[len(lines)] = "realms"
|
||||||
|
sectionLineNum = append(sectionLineNum, len(lines))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if matched, _ := regexp.MatchString(`^\s*\[domain_realm\]\s*`, scanner.Text()); matched {
|
||||||
|
sections[len(lines)] = "domain_realm"
|
||||||
|
sectionLineNum = append(sectionLineNum, len(lines))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if matched, _ := regexp.MatchString(`^\s*\[.*\]\s*`, scanner.Text()); matched {
|
||||||
|
sections[len(lines)] = "unknown_section"
|
||||||
|
sectionLineNum = append(sectionLineNum, len(lines))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
lines = append(lines, scanner.Text())
|
||||||
|
}
|
||||||
|
for i, start := range sectionLineNum {
|
||||||
|
var end int
|
||||||
|
if i+1 >= len(sectionLineNum) {
|
||||||
|
end = len(lines)
|
||||||
|
} else {
|
||||||
|
end = sectionLineNum[i+1]
|
||||||
|
}
|
||||||
|
switch section := sections[start]; section {
|
||||||
|
case "libdefaults":
|
||||||
|
err := c.LibDefaults.parseLines(lines[start:end])
|
||||||
|
if err != nil {
|
||||||
|
if _, ok := err.(UnsupportedDirective); !ok {
|
||||||
|
return nil, fmt.Errorf("error processing libdefaults section: %v", err)
|
||||||
|
}
|
||||||
|
e = err
|
||||||
|
}
|
||||||
|
case "realms":
|
||||||
|
realms, err := parseRealms(lines[start:end])
|
||||||
|
if err != nil {
|
||||||
|
if _, ok := err.(UnsupportedDirective); !ok {
|
||||||
|
return nil, fmt.Errorf("error processing realms section: %v", err)
|
||||||
|
}
|
||||||
|
e = err
|
||||||
|
}
|
||||||
|
c.Realms = realms
|
||||||
|
case "domain_realm":
|
||||||
|
err := c.DomainRealm.parseLines(lines[start:end])
|
||||||
|
if err != nil {
|
||||||
|
if _, ok := err.(UnsupportedDirective); !ok {
|
||||||
|
return nil, fmt.Errorf("error processing domaain_realm section: %v", err)
|
||||||
|
}
|
||||||
|
e = err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c, e
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse a space delimited list of ETypes into a list of EType numbers optionally filtering out weak ETypes.
|
||||||
|
func parseETypes(s []string, w bool) []int32 {
|
||||||
|
var eti []int32
|
||||||
|
for _, et := range s {
|
||||||
|
if !w {
|
||||||
|
var weak bool
|
||||||
|
for _, wet := range strings.Fields(WeakETypeList) {
|
||||||
|
if et == wet {
|
||||||
|
weak = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if weak {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i := etypeID.EtypeSupported(et)
|
||||||
|
if i != 0 {
|
||||||
|
eti = append(eti, i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return eti
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse a time duration string in the configuration to a golang time.Duration.
|
||||||
|
func parseDuration(s string) (time.Duration, error) {
|
||||||
|
s = strings.Replace(strings.TrimSpace(s), " ", "", -1)
|
||||||
|
|
||||||
|
// handle Nd[NmNs]
|
||||||
|
if strings.Contains(s, "d") {
|
||||||
|
ds := strings.SplitN(s, "d", 2)
|
||||||
|
dn, err := strconv.ParseUint(ds[0], 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
return time.Duration(0), errors.New("invalid time duration")
|
||||||
|
}
|
||||||
|
d := time.Duration(dn*24) * time.Hour
|
||||||
|
if ds[1] != "" {
|
||||||
|
dp, err := time.ParseDuration(ds[1])
|
||||||
|
if err != nil {
|
||||||
|
return time.Duration(0), errors.New("invalid time duration")
|
||||||
|
}
|
||||||
|
d = d + dp
|
||||||
|
}
|
||||||
|
return d, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle Nm[Ns]
|
||||||
|
d, err := time.ParseDuration(s)
|
||||||
|
if err == nil {
|
||||||
|
return d, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle N
|
||||||
|
v, err := strconv.ParseUint(s, 10, 32)
|
||||||
|
if err == nil && v > 0 {
|
||||||
|
return time.Duration(v) * time.Second, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle h:m[:s]
|
||||||
|
if strings.Contains(s, ":") {
|
||||||
|
t := strings.Split(s, ":")
|
||||||
|
if 2 > len(t) || len(t) > 3 {
|
||||||
|
return time.Duration(0), errors.New("invalid time duration value")
|
||||||
|
}
|
||||||
|
var i []int
|
||||||
|
for _, n := range t {
|
||||||
|
j, err := strconv.ParseInt(n, 10, 16)
|
||||||
|
if err != nil {
|
||||||
|
return time.Duration(0), errors.New("invalid time duration value")
|
||||||
|
}
|
||||||
|
i = append(i, int(j))
|
||||||
|
}
|
||||||
|
d := time.Duration(i[0])*time.Hour + time.Duration(i[1])*time.Minute
|
||||||
|
if len(i) == 3 {
|
||||||
|
d = d + time.Duration(i[2])*time.Second
|
||||||
|
}
|
||||||
|
return d, nil
|
||||||
|
}
|
||||||
|
return time.Duration(0), errors.New("invalid time duration value")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse possible boolean values to golang bool.
|
||||||
|
func parseBoolean(s string) (bool, error) {
|
||||||
|
s = strings.TrimSpace(s)
|
||||||
|
v, err := strconv.ParseBool(s)
|
||||||
|
if err == nil {
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
switch strings.ToLower(s) {
|
||||||
|
case "yes":
|
||||||
|
return true, nil
|
||||||
|
case "y":
|
||||||
|
return true, nil
|
||||||
|
case "no":
|
||||||
|
return false, nil
|
||||||
|
case "n":
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return false, errors.New("invalid boolean value")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse array of strings but stop if an asterisk is placed at the end of a line.
|
||||||
|
func appendUntilFinal(s *[]string, value string, final *bool) {
|
||||||
|
if *final {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if last := len(value) - 1; last >= 0 && value[last] == '*' {
|
||||||
|
*final = true
|
||||||
|
value = value[:len(value)-1]
|
||||||
|
}
|
||||||
|
*s = append(*s, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// JSON return details of the config in a JSON format.
|
||||||
|
func (c *Config) JSON() (string, error) {
|
||||||
|
b, err := json.MarshalIndent(c, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(b), nil
|
||||||
|
}
|
333
vendor/github.com/jcmturner/gokrb5/v8/credentials/ccache.go
generated
vendored
Normal file
333
vendor/github.com/jcmturner/gokrb5/v8/credentials/ccache.go
generated
vendored
Normal file
|
@ -0,0 +1,333 @@
|
||||||
|
package credentials
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
"io/ioutil"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/jcmturner/gofork/encoding/asn1"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
headerFieldTagKDCOffset = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
// CCache is the file credentials cache as define here: https://web.mit.edu/kerberos/krb5-latest/doc/formats/ccache_file_format.html
|
||||||
|
type CCache struct {
|
||||||
|
Version uint8
|
||||||
|
Header header
|
||||||
|
DefaultPrincipal principal
|
||||||
|
Credentials []*Credential
|
||||||
|
Path string
|
||||||
|
}
|
||||||
|
|
||||||
|
type header struct {
|
||||||
|
length uint16
|
||||||
|
fields []headerField
|
||||||
|
}
|
||||||
|
|
||||||
|
type headerField struct {
|
||||||
|
tag uint16
|
||||||
|
length uint16
|
||||||
|
value []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// Credential cache entry principal struct.
|
||||||
|
type principal struct {
|
||||||
|
Realm string
|
||||||
|
PrincipalName types.PrincipalName
|
||||||
|
}
|
||||||
|
|
||||||
|
// Credential holds a Kerberos client's ccache credential information.
|
||||||
|
type Credential struct {
|
||||||
|
Client principal
|
||||||
|
Server principal
|
||||||
|
Key types.EncryptionKey
|
||||||
|
AuthTime time.Time
|
||||||
|
StartTime time.Time
|
||||||
|
EndTime time.Time
|
||||||
|
RenewTill time.Time
|
||||||
|
IsSKey bool
|
||||||
|
TicketFlags asn1.BitString
|
||||||
|
Addresses []types.HostAddress
|
||||||
|
AuthData []types.AuthorizationDataEntry
|
||||||
|
Ticket []byte
|
||||||
|
SecondTicket []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadCCache loads a credential cache file into a CCache type.
|
||||||
|
func LoadCCache(cpath string) (*CCache, error) {
|
||||||
|
c := new(CCache)
|
||||||
|
b, err := ioutil.ReadFile(cpath)
|
||||||
|
if err != nil {
|
||||||
|
return c, err
|
||||||
|
}
|
||||||
|
err = c.Unmarshal(b)
|
||||||
|
return c, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshal a byte slice of credential cache data into CCache type.
|
||||||
|
func (c *CCache) Unmarshal(b []byte) error {
|
||||||
|
p := 0
|
||||||
|
//The first byte of the file always has the value 5
|
||||||
|
if int8(b[p]) != 5 {
|
||||||
|
return errors.New("Invalid credential cache data. First byte does not equal 5")
|
||||||
|
}
|
||||||
|
p++
|
||||||
|
//Get credential cache version
|
||||||
|
//The second byte contains the version number (1 to 4)
|
||||||
|
c.Version = b[p]
|
||||||
|
if c.Version < 1 || c.Version > 4 {
|
||||||
|
return errors.New("Invalid credential cache data. Keytab version is not within 1 to 4")
|
||||||
|
}
|
||||||
|
p++
|
||||||
|
//Version 1 or 2 of the file format uses native byte order for integer representations. Versions 3 & 4 always uses big-endian byte order
|
||||||
|
var endian binary.ByteOrder
|
||||||
|
endian = binary.BigEndian
|
||||||
|
if (c.Version == 1 || c.Version == 2) && isNativeEndianLittle() {
|
||||||
|
endian = binary.LittleEndian
|
||||||
|
}
|
||||||
|
if c.Version == 4 {
|
||||||
|
err := parseHeader(b, &p, c, &endian)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.DefaultPrincipal = parsePrincipal(b, &p, c, &endian)
|
||||||
|
for p < len(b) {
|
||||||
|
cred, err := parseCredential(b, &p, c, &endian)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.Credentials = append(c.Credentials, cred)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseHeader(b []byte, p *int, c *CCache, e *binary.ByteOrder) error {
|
||||||
|
if c.Version != 4 {
|
||||||
|
return errors.New("Credentials cache version is not 4 so there is no header to parse.")
|
||||||
|
}
|
||||||
|
h := header{}
|
||||||
|
h.length = uint16(readInt16(b, p, e))
|
||||||
|
for *p <= int(h.length) {
|
||||||
|
f := headerField{}
|
||||||
|
f.tag = uint16(readInt16(b, p, e))
|
||||||
|
f.length = uint16(readInt16(b, p, e))
|
||||||
|
f.value = b[*p : *p+int(f.length)]
|
||||||
|
*p += int(f.length)
|
||||||
|
if !f.valid() {
|
||||||
|
return errors.New("Invalid credential cache header found")
|
||||||
|
}
|
||||||
|
h.fields = append(h.fields, f)
|
||||||
|
}
|
||||||
|
c.Header = h
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the Keytab bytes of a principal into a Keytab entry's principal.
|
||||||
|
func parsePrincipal(b []byte, p *int, c *CCache, e *binary.ByteOrder) (princ principal) {
|
||||||
|
if c.Version != 1 {
|
||||||
|
//Name Type is omitted in version 1
|
||||||
|
princ.PrincipalName.NameType = readInt32(b, p, e)
|
||||||
|
}
|
||||||
|
nc := int(readInt32(b, p, e))
|
||||||
|
if c.Version == 1 {
|
||||||
|
//In version 1 the number of components includes the realm. Minus 1 to make consistent with version 2
|
||||||
|
nc--
|
||||||
|
}
|
||||||
|
lenRealm := readInt32(b, p, e)
|
||||||
|
princ.Realm = string(readBytes(b, p, int(lenRealm), e))
|
||||||
|
for i := 0; i < nc; i++ {
|
||||||
|
l := readInt32(b, p, e)
|
||||||
|
princ.PrincipalName.NameString = append(princ.PrincipalName.NameString, string(readBytes(b, p, int(l), e)))
|
||||||
|
}
|
||||||
|
return princ
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseCredential(b []byte, p *int, c *CCache, e *binary.ByteOrder) (cred *Credential, err error) {
|
||||||
|
cred = new(Credential)
|
||||||
|
cred.Client = parsePrincipal(b, p, c, e)
|
||||||
|
cred.Server = parsePrincipal(b, p, c, e)
|
||||||
|
key := types.EncryptionKey{}
|
||||||
|
key.KeyType = int32(readInt16(b, p, e))
|
||||||
|
if c.Version == 3 {
|
||||||
|
//repeated twice in version 3
|
||||||
|
key.KeyType = int32(readInt16(b, p, e))
|
||||||
|
}
|
||||||
|
key.KeyValue = readData(b, p, e)
|
||||||
|
cred.Key = key
|
||||||
|
cred.AuthTime = readTimestamp(b, p, e)
|
||||||
|
cred.StartTime = readTimestamp(b, p, e)
|
||||||
|
cred.EndTime = readTimestamp(b, p, e)
|
||||||
|
cred.RenewTill = readTimestamp(b, p, e)
|
||||||
|
if ik := readInt8(b, p, e); ik == 0 {
|
||||||
|
cred.IsSKey = false
|
||||||
|
} else {
|
||||||
|
cred.IsSKey = true
|
||||||
|
}
|
||||||
|
cred.TicketFlags = types.NewKrbFlags()
|
||||||
|
cred.TicketFlags.Bytes = readBytes(b, p, 4, e)
|
||||||
|
l := int(readInt32(b, p, e))
|
||||||
|
cred.Addresses = make([]types.HostAddress, l, l)
|
||||||
|
for i := range cred.Addresses {
|
||||||
|
cred.Addresses[i] = readAddress(b, p, e)
|
||||||
|
}
|
||||||
|
l = int(readInt32(b, p, e))
|
||||||
|
cred.AuthData = make([]types.AuthorizationDataEntry, l, l)
|
||||||
|
for i := range cred.AuthData {
|
||||||
|
cred.AuthData[i] = readAuthDataEntry(b, p, e)
|
||||||
|
}
|
||||||
|
cred.Ticket = readData(b, p, e)
|
||||||
|
cred.SecondTicket = readData(b, p, e)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetClientPrincipalName returns a PrincipalName type for the client the credentials cache is for.
|
||||||
|
func (c *CCache) GetClientPrincipalName() types.PrincipalName {
|
||||||
|
return c.DefaultPrincipal.PrincipalName
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetClientRealm returns the reals of the client the credentials cache is for.
|
||||||
|
func (c *CCache) GetClientRealm() string {
|
||||||
|
return c.DefaultPrincipal.Realm
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetClientCredentials returns a Credentials object representing the client of the credentials cache.
|
||||||
|
func (c *CCache) GetClientCredentials() *Credentials {
|
||||||
|
return &Credentials{
|
||||||
|
username: c.DefaultPrincipal.PrincipalName.PrincipalNameString(),
|
||||||
|
realm: c.GetClientRealm(),
|
||||||
|
cname: c.DefaultPrincipal.PrincipalName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Contains tests if the cache contains a credential for the provided server PrincipalName
|
||||||
|
func (c *CCache) Contains(p types.PrincipalName) bool {
|
||||||
|
for _, cred := range c.Credentials {
|
||||||
|
if cred.Server.PrincipalName.Equal(p) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetEntry returns a specific credential for the PrincipalName provided.
|
||||||
|
func (c *CCache) GetEntry(p types.PrincipalName) (*Credential, bool) {
|
||||||
|
cred := new(Credential)
|
||||||
|
var found bool
|
||||||
|
for i := range c.Credentials {
|
||||||
|
if c.Credentials[i].Server.PrincipalName.Equal(p) {
|
||||||
|
cred = c.Credentials[i]
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
return cred, false
|
||||||
|
}
|
||||||
|
return cred, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetEntries filters out configuration entries an returns a slice of credentials.
|
||||||
|
func (c *CCache) GetEntries() []*Credential {
|
||||||
|
creds := make([]*Credential, 0)
|
||||||
|
for _, cred := range c.Credentials {
|
||||||
|
// Filter out configuration entries
|
||||||
|
if strings.HasPrefix(cred.Server.Realm, "X-CACHECONF") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
creds = append(creds, cred)
|
||||||
|
}
|
||||||
|
return creds
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *headerField) valid() bool {
|
||||||
|
// See https://web.mit.edu/kerberos/krb5-latest/doc/formats/ccache_file_format.html - Header format
|
||||||
|
switch h.tag {
|
||||||
|
case headerFieldTagKDCOffset:
|
||||||
|
if h.length != 8 || len(h.value) != 8 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func readData(b []byte, p *int, e *binary.ByteOrder) []byte {
|
||||||
|
l := readInt32(b, p, e)
|
||||||
|
return readBytes(b, p, int(l), e)
|
||||||
|
}
|
||||||
|
|
||||||
|
func readAddress(b []byte, p *int, e *binary.ByteOrder) types.HostAddress {
|
||||||
|
a := types.HostAddress{}
|
||||||
|
a.AddrType = int32(readInt16(b, p, e))
|
||||||
|
a.Address = readData(b, p, e)
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
func readAuthDataEntry(b []byte, p *int, e *binary.ByteOrder) types.AuthorizationDataEntry {
|
||||||
|
a := types.AuthorizationDataEntry{}
|
||||||
|
a.ADType = int32(readInt16(b, p, e))
|
||||||
|
a.ADData = readData(b, p, e)
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read bytes representing a timestamp.
|
||||||
|
func readTimestamp(b []byte, p *int, e *binary.ByteOrder) time.Time {
|
||||||
|
return time.Unix(int64(readInt32(b, p, e)), 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read bytes representing an eight bit integer.
|
||||||
|
func readInt8(b []byte, p *int, e *binary.ByteOrder) (i int8) {
|
||||||
|
buf := bytes.NewBuffer(b[*p : *p+1])
|
||||||
|
binary.Read(buf, *e, &i)
|
||||||
|
*p++
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read bytes representing a sixteen bit integer.
|
||||||
|
func readInt16(b []byte, p *int, e *binary.ByteOrder) (i int16) {
|
||||||
|
buf := bytes.NewBuffer(b[*p : *p+2])
|
||||||
|
binary.Read(buf, *e, &i)
|
||||||
|
*p += 2
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read bytes representing a thirty two bit integer.
|
||||||
|
func readInt32(b []byte, p *int, e *binary.ByteOrder) (i int32) {
|
||||||
|
buf := bytes.NewBuffer(b[*p : *p+4])
|
||||||
|
binary.Read(buf, *e, &i)
|
||||||
|
*p += 4
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func readBytes(b []byte, p *int, s int, e *binary.ByteOrder) []byte {
|
||||||
|
buf := bytes.NewBuffer(b[*p : *p+s])
|
||||||
|
r := make([]byte, s)
|
||||||
|
binary.Read(buf, *e, &r)
|
||||||
|
*p += s
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func isNativeEndianLittle() bool {
|
||||||
|
var x = 0x012345678
|
||||||
|
var p = unsafe.Pointer(&x)
|
||||||
|
var bp = (*[4]byte)(p)
|
||||||
|
|
||||||
|
var endian bool
|
||||||
|
if 0x01 == bp[0] {
|
||||||
|
endian = false
|
||||||
|
} else if (0x78 & 0xff) == (bp[0] & 0xff) {
|
||||||
|
endian = true
|
||||||
|
} else {
|
||||||
|
// Default to big endian
|
||||||
|
endian = false
|
||||||
|
}
|
||||||
|
return endian
|
||||||
|
}
|
405
vendor/github.com/jcmturner/gokrb5/v8/credentials/credentials.go
generated
vendored
Normal file
405
vendor/github.com/jcmturner/gokrb5/v8/credentials/credentials.go
generated
vendored
Normal file
|
@ -0,0 +1,405 @@
|
||||||
|
// Package credentials provides credentials management for Kerberos 5 authentication.
|
||||||
|
package credentials
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/gob"
|
||||||
|
"encoding/json"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/hashicorp/go-uuid"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/nametype"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/keytab"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// AttributeKeyADCredentials assigned number for AD credentials.
|
||||||
|
AttributeKeyADCredentials = "gokrb5AttributeKeyADCredentials"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Credentials struct for a user.
|
||||||
|
// Contains either a keytab, password or both.
|
||||||
|
// Keytabs are used over passwords if both are defined.
|
||||||
|
type Credentials struct {
|
||||||
|
username string
|
||||||
|
displayName string
|
||||||
|
realm string
|
||||||
|
cname types.PrincipalName
|
||||||
|
keytab *keytab.Keytab
|
||||||
|
password string
|
||||||
|
attributes map[string]interface{}
|
||||||
|
validUntil time.Time
|
||||||
|
authenticated bool
|
||||||
|
human bool
|
||||||
|
authTime time.Time
|
||||||
|
groupMembership map[string]bool
|
||||||
|
sessionID string
|
||||||
|
}
|
||||||
|
|
||||||
|
// marshalCredentials is used to enable marshaling and unmarshaling of credentials
|
||||||
|
// without having exported fields on the Credentials struct
|
||||||
|
type marshalCredentials struct {
|
||||||
|
Username string
|
||||||
|
DisplayName string
|
||||||
|
Realm string
|
||||||
|
CName types.PrincipalName `json:"-"`
|
||||||
|
Keytab bool
|
||||||
|
Password bool
|
||||||
|
Attributes map[string]interface{} `json:"-"`
|
||||||
|
ValidUntil time.Time
|
||||||
|
Authenticated bool
|
||||||
|
Human bool
|
||||||
|
AuthTime time.Time
|
||||||
|
GroupMembership map[string]bool `json:"-"`
|
||||||
|
SessionID string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ADCredentials contains information obtained from the PAC.
|
||||||
|
type ADCredentials struct {
|
||||||
|
EffectiveName string
|
||||||
|
FullName string
|
||||||
|
UserID int
|
||||||
|
PrimaryGroupID int
|
||||||
|
LogOnTime time.Time
|
||||||
|
LogOffTime time.Time
|
||||||
|
PasswordLastSet time.Time
|
||||||
|
GroupMembershipSIDs []string
|
||||||
|
LogonDomainName string
|
||||||
|
LogonDomainID string
|
||||||
|
LogonServer string
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates a new Credentials instance.
|
||||||
|
func New(username string, realm string) *Credentials {
|
||||||
|
uid, err := uuid.GenerateUUID()
|
||||||
|
if err != nil {
|
||||||
|
uid = "00unique-sess-ions-uuid-unavailable0"
|
||||||
|
}
|
||||||
|
return &Credentials{
|
||||||
|
username: username,
|
||||||
|
displayName: username,
|
||||||
|
realm: realm,
|
||||||
|
cname: types.NewPrincipalName(nametype.KRB_NT_PRINCIPAL, username),
|
||||||
|
keytab: keytab.New(),
|
||||||
|
attributes: make(map[string]interface{}),
|
||||||
|
groupMembership: make(map[string]bool),
|
||||||
|
sessionID: uid,
|
||||||
|
human: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFromPrincipalName creates a new Credentials instance with the user details provides as a PrincipalName type.
|
||||||
|
func NewFromPrincipalName(cname types.PrincipalName, realm string) *Credentials {
|
||||||
|
c := New(cname.PrincipalNameString(), realm)
|
||||||
|
c.cname = cname
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithKeytab sets the Keytab in the Credentials struct.
|
||||||
|
func (c *Credentials) WithKeytab(kt *keytab.Keytab) *Credentials {
|
||||||
|
c.keytab = kt
|
||||||
|
c.password = ""
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keytab returns the credential's Keytab.
|
||||||
|
func (c *Credentials) Keytab() *keytab.Keytab {
|
||||||
|
return c.keytab
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasKeytab queries if the Credentials has a keytab defined.
|
||||||
|
func (c *Credentials) HasKeytab() bool {
|
||||||
|
if c.keytab != nil && len(c.keytab.Entries) > 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithPassword sets the password in the Credentials struct.
|
||||||
|
func (c *Credentials) WithPassword(password string) *Credentials {
|
||||||
|
c.password = password
|
||||||
|
c.keytab = keytab.New() // clear any keytab
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// Password returns the credential's password.
|
||||||
|
func (c *Credentials) Password() string {
|
||||||
|
return c.password
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasPassword queries if the Credentials has a password defined.
|
||||||
|
func (c *Credentials) HasPassword() bool {
|
||||||
|
if c.password != "" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetValidUntil sets the expiry time of the credentials
|
||||||
|
func (c *Credentials) SetValidUntil(t time.Time) {
|
||||||
|
c.validUntil = t
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetADCredentials adds ADCredentials attributes to the credentials
|
||||||
|
func (c *Credentials) SetADCredentials(a ADCredentials) {
|
||||||
|
c.SetAttribute(AttributeKeyADCredentials, a)
|
||||||
|
if a.FullName != "" {
|
||||||
|
c.SetDisplayName(a.FullName)
|
||||||
|
}
|
||||||
|
if a.EffectiveName != "" {
|
||||||
|
c.SetUserName(a.EffectiveName)
|
||||||
|
}
|
||||||
|
for i := range a.GroupMembershipSIDs {
|
||||||
|
c.AddAuthzAttribute(a.GroupMembershipSIDs[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetADCredentials returns ADCredentials attributes sorted in the credential
|
||||||
|
func (c *Credentials) GetADCredentials() ADCredentials {
|
||||||
|
if a, ok := c.attributes[AttributeKeyADCredentials].(ADCredentials); ok {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
return ADCredentials{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Methods to implement goidentity.Identity interface
|
||||||
|
|
||||||
|
// UserName returns the credential's username.
|
||||||
|
func (c *Credentials) UserName() string {
|
||||||
|
return c.username
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetUserName sets the username value on the credential.
|
||||||
|
func (c *Credentials) SetUserName(s string) {
|
||||||
|
c.username = s
|
||||||
|
}
|
||||||
|
|
||||||
|
// CName returns the credential's client principal name.
|
||||||
|
func (c *Credentials) CName() types.PrincipalName {
|
||||||
|
return c.cname
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetCName sets the client principal name on the credential.
|
||||||
|
func (c *Credentials) SetCName(pn types.PrincipalName) {
|
||||||
|
c.cname = pn
|
||||||
|
}
|
||||||
|
|
||||||
|
// Domain returns the credential's domain.
|
||||||
|
func (c *Credentials) Domain() string {
|
||||||
|
return c.realm
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetDomain sets the domain value on the credential.
|
||||||
|
func (c *Credentials) SetDomain(s string) {
|
||||||
|
c.realm = s
|
||||||
|
}
|
||||||
|
|
||||||
|
// Realm returns the credential's realm. Same as the domain.
|
||||||
|
func (c *Credentials) Realm() string {
|
||||||
|
return c.Domain()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetRealm sets the realm value on the credential. Same as the domain
|
||||||
|
func (c *Credentials) SetRealm(s string) {
|
||||||
|
c.SetDomain(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DisplayName returns the credential's display name.
|
||||||
|
func (c *Credentials) DisplayName() string {
|
||||||
|
return c.displayName
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetDisplayName sets the display name value on the credential.
|
||||||
|
func (c *Credentials) SetDisplayName(s string) {
|
||||||
|
c.displayName = s
|
||||||
|
}
|
||||||
|
|
||||||
|
// Human returns if the credential represents a human or not.
|
||||||
|
func (c *Credentials) Human() bool {
|
||||||
|
return c.human
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetHuman sets the credential as human.
|
||||||
|
func (c *Credentials) SetHuman(b bool) {
|
||||||
|
c.human = b
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthTime returns the time the credential was authenticated.
|
||||||
|
func (c *Credentials) AuthTime() time.Time {
|
||||||
|
return c.authTime
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetAuthTime sets the time the credential was authenticated.
|
||||||
|
func (c *Credentials) SetAuthTime(t time.Time) {
|
||||||
|
c.authTime = t
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthzAttributes returns the credentials authorizing attributes.
|
||||||
|
func (c *Credentials) AuthzAttributes() []string {
|
||||||
|
s := make([]string, len(c.groupMembership))
|
||||||
|
i := 0
|
||||||
|
for a := range c.groupMembership {
|
||||||
|
s[i] = a
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// Authenticated indicates if the credential has been successfully authenticated or not.
|
||||||
|
func (c *Credentials) Authenticated() bool {
|
||||||
|
return c.authenticated
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetAuthenticated sets the credential as having been successfully authenticated.
|
||||||
|
func (c *Credentials) SetAuthenticated(b bool) {
|
||||||
|
c.authenticated = b
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddAuthzAttribute adds an authorization attribute to the credential.
|
||||||
|
func (c *Credentials) AddAuthzAttribute(a string) {
|
||||||
|
c.groupMembership[a] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveAuthzAttribute removes an authorization attribute from the credential.
|
||||||
|
func (c *Credentials) RemoveAuthzAttribute(a string) {
|
||||||
|
if _, ok := c.groupMembership[a]; !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
delete(c.groupMembership, a)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnableAuthzAttribute toggles an authorization attribute to an enabled state on the credential.
|
||||||
|
func (c *Credentials) EnableAuthzAttribute(a string) {
|
||||||
|
if enabled, ok := c.groupMembership[a]; ok && !enabled {
|
||||||
|
c.groupMembership[a] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DisableAuthzAttribute toggles an authorization attribute to a disabled state on the credential.
|
||||||
|
func (c *Credentials) DisableAuthzAttribute(a string) {
|
||||||
|
if enabled, ok := c.groupMembership[a]; ok && enabled {
|
||||||
|
c.groupMembership[a] = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Authorized indicates if the credential has the specified authorizing attribute.
|
||||||
|
func (c *Credentials) Authorized(a string) bool {
|
||||||
|
if enabled, ok := c.groupMembership[a]; ok && enabled {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// SessionID returns the credential's session ID.
|
||||||
|
func (c *Credentials) SessionID() string {
|
||||||
|
return c.sessionID
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expired indicates if the credential has expired.
|
||||||
|
func (c *Credentials) Expired() bool {
|
||||||
|
if !c.validUntil.IsZero() && time.Now().UTC().After(c.validUntil) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidUntil returns the credential's valid until date
|
||||||
|
func (c *Credentials) ValidUntil() time.Time {
|
||||||
|
return c.validUntil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attributes returns the Credentials' attributes map.
|
||||||
|
func (c *Credentials) Attributes() map[string]interface{} {
|
||||||
|
return c.attributes
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetAttribute sets the value of an attribute.
|
||||||
|
func (c *Credentials) SetAttribute(k string, v interface{}) {
|
||||||
|
c.attributes[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetAttributes replaces the attributes map with the one provided.
|
||||||
|
func (c *Credentials) SetAttributes(a map[string]interface{}) {
|
||||||
|
c.attributes = a
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveAttribute deletes an attribute from the attribute map that has the key provided.
|
||||||
|
func (c *Credentials) RemoveAttribute(k string) {
|
||||||
|
delete(c.attributes, k)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marshal the Credentials into a byte slice
|
||||||
|
func (c *Credentials) Marshal() ([]byte, error) {
|
||||||
|
gob.Register(map[string]interface{}{})
|
||||||
|
gob.Register(ADCredentials{})
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
enc := gob.NewEncoder(buf)
|
||||||
|
mc := marshalCredentials{
|
||||||
|
Username: c.username,
|
||||||
|
DisplayName: c.displayName,
|
||||||
|
Realm: c.realm,
|
||||||
|
CName: c.cname,
|
||||||
|
Keytab: c.HasKeytab(),
|
||||||
|
Password: c.HasPassword(),
|
||||||
|
Attributes: c.attributes,
|
||||||
|
ValidUntil: c.validUntil,
|
||||||
|
Authenticated: c.authenticated,
|
||||||
|
Human: c.human,
|
||||||
|
AuthTime: c.authTime,
|
||||||
|
GroupMembership: c.groupMembership,
|
||||||
|
SessionID: c.sessionID,
|
||||||
|
}
|
||||||
|
err := enc.Encode(&mc)
|
||||||
|
if err != nil {
|
||||||
|
return []byte{}, err
|
||||||
|
}
|
||||||
|
return buf.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshal a byte slice into Credentials
|
||||||
|
func (c *Credentials) Unmarshal(b []byte) error {
|
||||||
|
gob.Register(map[string]interface{}{})
|
||||||
|
gob.Register(ADCredentials{})
|
||||||
|
mc := new(marshalCredentials)
|
||||||
|
buf := bytes.NewBuffer(b)
|
||||||
|
dec := gob.NewDecoder(buf)
|
||||||
|
err := dec.Decode(mc)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.username = mc.Username
|
||||||
|
c.displayName = mc.DisplayName
|
||||||
|
c.realm = mc.Realm
|
||||||
|
c.cname = mc.CName
|
||||||
|
c.attributes = mc.Attributes
|
||||||
|
c.validUntil = mc.ValidUntil
|
||||||
|
c.authenticated = mc.Authenticated
|
||||||
|
c.human = mc.Human
|
||||||
|
c.authTime = mc.AuthTime
|
||||||
|
c.groupMembership = mc.GroupMembership
|
||||||
|
c.sessionID = mc.SessionID
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// JSON return details of the Credentials in a JSON format.
|
||||||
|
func (c *Credentials) JSON() (string, error) {
|
||||||
|
mc := marshalCredentials{
|
||||||
|
Username: c.username,
|
||||||
|
DisplayName: c.displayName,
|
||||||
|
Realm: c.realm,
|
||||||
|
CName: c.cname,
|
||||||
|
Keytab: c.HasKeytab(),
|
||||||
|
Password: c.HasPassword(),
|
||||||
|
ValidUntil: c.validUntil,
|
||||||
|
Authenticated: c.authenticated,
|
||||||
|
Human: c.human,
|
||||||
|
AuthTime: c.authTime,
|
||||||
|
SessionID: c.sessionID,
|
||||||
|
}
|
||||||
|
b, err := json.MarshalIndent(mc, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(b), nil
|
||||||
|
}
|
129
vendor/github.com/jcmturner/gokrb5/v8/crypto/aes128-cts-hmac-sha1-96.go
generated
vendored
Normal file
129
vendor/github.com/jcmturner/gokrb5/v8/crypto/aes128-cts-hmac-sha1-96.go
generated
vendored
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
package crypto
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/aes"
|
||||||
|
"crypto/hmac"
|
||||||
|
"crypto/sha1"
|
||||||
|
"hash"
|
||||||
|
|
||||||
|
"github.com/jcmturner/gokrb5/v8/crypto/common"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/crypto/rfc3961"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/crypto/rfc3962"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/chksumtype"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/etypeID"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RFC 3962
|
||||||
|
|
||||||
|
// Aes128CtsHmacSha96 implements Kerberos encryption type aes128-cts-hmac-sha1-96
|
||||||
|
type Aes128CtsHmacSha96 struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetETypeID returns the EType ID number.
|
||||||
|
func (e Aes128CtsHmacSha96) GetETypeID() int32 {
|
||||||
|
return etypeID.AES128_CTS_HMAC_SHA1_96
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHashID returns the checksum type ID number.
|
||||||
|
func (e Aes128CtsHmacSha96) GetHashID() int32 {
|
||||||
|
return chksumtype.HMAC_SHA1_96_AES128
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetKeyByteSize returns the number of bytes for key of this etype.
|
||||||
|
func (e Aes128CtsHmacSha96) GetKeyByteSize() int {
|
||||||
|
return 128 / 8
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetKeySeedBitLength returns the number of bits for the seed for key generation.
|
||||||
|
func (e Aes128CtsHmacSha96) GetKeySeedBitLength() int {
|
||||||
|
return e.GetKeyByteSize() * 8
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHashFunc returns the hash function for this etype.
|
||||||
|
func (e Aes128CtsHmacSha96) GetHashFunc() func() hash.Hash {
|
||||||
|
return sha1.New
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMessageBlockByteSize returns the block size for the etype's messages.
|
||||||
|
func (e Aes128CtsHmacSha96) GetMessageBlockByteSize() int {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDefaultStringToKeyParams returns the default key derivation parameters in string form.
|
||||||
|
func (e Aes128CtsHmacSha96) GetDefaultStringToKeyParams() string {
|
||||||
|
return "00001000"
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetConfounderByteSize returns the byte count for confounder to be used during cryptographic operations.
|
||||||
|
func (e Aes128CtsHmacSha96) GetConfounderByteSize() int {
|
||||||
|
return aes.BlockSize
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHMACBitLength returns the bit count size of the integrity hash.
|
||||||
|
func (e Aes128CtsHmacSha96) GetHMACBitLength() int {
|
||||||
|
return 96
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCypherBlockBitLength returns the bit count size of the cypher block.
|
||||||
|
func (e Aes128CtsHmacSha96) GetCypherBlockBitLength() int {
|
||||||
|
return aes.BlockSize * 8
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringToKey returns a key derived from the string provided.
|
||||||
|
func (e Aes128CtsHmacSha96) StringToKey(secret string, salt string, s2kparams string) ([]byte, error) {
|
||||||
|
return rfc3962.StringToKey(secret, salt, s2kparams, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RandomToKey returns a key from the bytes provided.
|
||||||
|
func (e Aes128CtsHmacSha96) RandomToKey(b []byte) []byte {
|
||||||
|
return rfc3961.RandomToKey(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncryptData encrypts the data provided.
|
||||||
|
func (e Aes128CtsHmacSha96) EncryptData(key, data []byte) ([]byte, []byte, error) {
|
||||||
|
return rfc3962.EncryptData(key, data, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncryptMessage encrypts the message provided and concatenates it with the integrity hash to create an encrypted message.
|
||||||
|
func (e Aes128CtsHmacSha96) EncryptMessage(key, message []byte, usage uint32) ([]byte, []byte, error) {
|
||||||
|
return rfc3962.EncryptMessage(key, message, usage, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecryptData decrypts the data provided.
|
||||||
|
func (e Aes128CtsHmacSha96) DecryptData(key, data []byte) ([]byte, error) {
|
||||||
|
return rfc3962.DecryptData(key, data, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecryptMessage decrypts the message provided and verifies the integrity of the message.
|
||||||
|
func (e Aes128CtsHmacSha96) DecryptMessage(key, ciphertext []byte, usage uint32) ([]byte, error) {
|
||||||
|
return rfc3962.DecryptMessage(key, ciphertext, usage, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeriveKey derives a key from the protocol key based on the usage value.
|
||||||
|
func (e Aes128CtsHmacSha96) DeriveKey(protocolKey, usage []byte) ([]byte, error) {
|
||||||
|
return rfc3961.DeriveKey(protocolKey, usage, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeriveRandom generates data needed for key generation.
|
||||||
|
func (e Aes128CtsHmacSha96) DeriveRandom(protocolKey, usage []byte) ([]byte, error) {
|
||||||
|
return rfc3961.DeriveRandom(protocolKey, usage, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyIntegrity checks the integrity of the plaintext message.
|
||||||
|
func (e Aes128CtsHmacSha96) VerifyIntegrity(protocolKey, ct, pt []byte, usage uint32) bool {
|
||||||
|
return rfc3961.VerifyIntegrity(protocolKey, ct, pt, usage, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetChecksumHash returns a keyed checksum hash of the bytes provided.
|
||||||
|
func (e Aes128CtsHmacSha96) GetChecksumHash(protocolKey, data []byte, usage uint32) ([]byte, error) {
|
||||||
|
return common.GetHash(data, protocolKey, common.GetUsageKc(usage), e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyChecksum compares the checksum of the message bytes is the same as the checksum provided.
|
||||||
|
func (e Aes128CtsHmacSha96) VerifyChecksum(protocolKey, data, chksum []byte, usage uint32) bool {
|
||||||
|
c, err := e.GetChecksumHash(protocolKey, data, usage)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return hmac.Equal(chksum, c)
|
||||||
|
}
|
132
vendor/github.com/jcmturner/gokrb5/v8/crypto/aes128-cts-hmac-sha256-128.go
generated
vendored
Normal file
132
vendor/github.com/jcmturner/gokrb5/v8/crypto/aes128-cts-hmac-sha256-128.go
generated
vendored
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
package crypto
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/aes"
|
||||||
|
"crypto/hmac"
|
||||||
|
"crypto/sha256"
|
||||||
|
"hash"
|
||||||
|
|
||||||
|
"github.com/jcmturner/gokrb5/v8/crypto/common"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/crypto/rfc8009"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/chksumtype"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/etypeID"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RFC https://tools.ietf.org/html/rfc8009
|
||||||
|
|
||||||
|
// Aes128CtsHmacSha256128 implements Kerberos encryption type aes128-cts-hmac-sha256-128
|
||||||
|
type Aes128CtsHmacSha256128 struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetETypeID returns the EType ID number.
|
||||||
|
func (e Aes128CtsHmacSha256128) GetETypeID() int32 {
|
||||||
|
return etypeID.AES128_CTS_HMAC_SHA256_128
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHashID returns the checksum type ID number.
|
||||||
|
func (e Aes128CtsHmacSha256128) GetHashID() int32 {
|
||||||
|
return chksumtype.HMAC_SHA256_128_AES128
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetKeyByteSize returns the number of bytes for key of this etype.
|
||||||
|
func (e Aes128CtsHmacSha256128) GetKeyByteSize() int {
|
||||||
|
return 128 / 8
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetKeySeedBitLength returns the number of bits for the seed for key generation.
|
||||||
|
func (e Aes128CtsHmacSha256128) GetKeySeedBitLength() int {
|
||||||
|
return e.GetKeyByteSize() * 8
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHashFunc returns the hash function for this etype.
|
||||||
|
func (e Aes128CtsHmacSha256128) GetHashFunc() func() hash.Hash {
|
||||||
|
return sha256.New
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMessageBlockByteSize returns the block size for the etype's messages.
|
||||||
|
func (e Aes128CtsHmacSha256128) GetMessageBlockByteSize() int {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDefaultStringToKeyParams returns the default key derivation parameters in string form.
|
||||||
|
func (e Aes128CtsHmacSha256128) GetDefaultStringToKeyParams() string {
|
||||||
|
return "00008000"
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetConfounderByteSize returns the byte count for confounder to be used during cryptographic operations.
|
||||||
|
func (e Aes128CtsHmacSha256128) GetConfounderByteSize() int {
|
||||||
|
return aes.BlockSize
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHMACBitLength returns the bit count size of the integrity hash.
|
||||||
|
func (e Aes128CtsHmacSha256128) GetHMACBitLength() int {
|
||||||
|
return 128
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCypherBlockBitLength returns the bit count size of the cypher block.
|
||||||
|
func (e Aes128CtsHmacSha256128) GetCypherBlockBitLength() int {
|
||||||
|
return aes.BlockSize * 8
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringToKey returns a key derived from the string provided.
|
||||||
|
func (e Aes128CtsHmacSha256128) StringToKey(secret string, salt string, s2kparams string) ([]byte, error) {
|
||||||
|
saltp := rfc8009.GetSaltP(salt, "aes128-cts-hmac-sha256-128")
|
||||||
|
return rfc8009.StringToKey(secret, saltp, s2kparams, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RandomToKey returns a key from the bytes provided.
|
||||||
|
func (e Aes128CtsHmacSha256128) RandomToKey(b []byte) []byte {
|
||||||
|
return rfc8009.RandomToKey(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncryptData encrypts the data provided.
|
||||||
|
func (e Aes128CtsHmacSha256128) EncryptData(key, data []byte) ([]byte, []byte, error) {
|
||||||
|
return rfc8009.EncryptData(key, data, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncryptMessage encrypts the message provided and concatenates it with the integrity hash to create an encrypted message.
|
||||||
|
func (e Aes128CtsHmacSha256128) EncryptMessage(key, message []byte, usage uint32) ([]byte, []byte, error) {
|
||||||
|
return rfc8009.EncryptMessage(key, message, usage, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecryptData decrypts the data provided.
|
||||||
|
func (e Aes128CtsHmacSha256128) DecryptData(key, data []byte) ([]byte, error) {
|
||||||
|
return rfc8009.DecryptData(key, data, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecryptMessage decrypts the message provided and verifies the integrity of the message.
|
||||||
|
func (e Aes128CtsHmacSha256128) DecryptMessage(key, ciphertext []byte, usage uint32) ([]byte, error) {
|
||||||
|
return rfc8009.DecryptMessage(key, ciphertext, usage, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeriveKey derives a key from the protocol key based on the usage value.
|
||||||
|
func (e Aes128CtsHmacSha256128) DeriveKey(protocolKey, usage []byte) ([]byte, error) {
|
||||||
|
return rfc8009.DeriveKey(protocolKey, usage, e), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeriveRandom generates data needed for key generation.
|
||||||
|
func (e Aes128CtsHmacSha256128) DeriveRandom(protocolKey, usage []byte) ([]byte, error) {
|
||||||
|
return rfc8009.DeriveRandom(protocolKey, usage, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyIntegrity checks the integrity of the ciphertext message.
|
||||||
|
// As the hash is calculated over the iv concatenated with the AES cipher output not the plaintext the pt value to this
|
||||||
|
// interface method is not use. Pass any []byte.
|
||||||
|
func (e Aes128CtsHmacSha256128) VerifyIntegrity(protocolKey, ct, pt []byte, usage uint32) bool {
|
||||||
|
// We don't need ib just there for the interface
|
||||||
|
return rfc8009.VerifyIntegrity(protocolKey, ct, usage, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetChecksumHash returns a keyed checksum hash of the bytes provided.
|
||||||
|
func (e Aes128CtsHmacSha256128) GetChecksumHash(protocolKey, data []byte, usage uint32) ([]byte, error) {
|
||||||
|
return common.GetHash(data, protocolKey, common.GetUsageKc(usage), e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyChecksum compares the checksum of the message bytes is the same as the checksum provided.
|
||||||
|
func (e Aes128CtsHmacSha256128) VerifyChecksum(protocolKey, data, chksum []byte, usage uint32) bool {
|
||||||
|
c, err := e.GetChecksumHash(protocolKey, data, usage)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return hmac.Equal(chksum, c)
|
||||||
|
}
|
129
vendor/github.com/jcmturner/gokrb5/v8/crypto/aes256-cts-hmac-sha1-96.go
generated
vendored
Normal file
129
vendor/github.com/jcmturner/gokrb5/v8/crypto/aes256-cts-hmac-sha1-96.go
generated
vendored
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
package crypto
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/aes"
|
||||||
|
"crypto/hmac"
|
||||||
|
"crypto/sha1"
|
||||||
|
"hash"
|
||||||
|
|
||||||
|
"github.com/jcmturner/gokrb5/v8/crypto/common"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/crypto/rfc3961"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/crypto/rfc3962"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/chksumtype"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/etypeID"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RFC 3962
|
||||||
|
|
||||||
|
// Aes256CtsHmacSha96 implements Kerberos encryption type aes256-cts-hmac-sha1-96
|
||||||
|
type Aes256CtsHmacSha96 struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetETypeID returns the EType ID number.
|
||||||
|
func (e Aes256CtsHmacSha96) GetETypeID() int32 {
|
||||||
|
return etypeID.AES256_CTS_HMAC_SHA1_96
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHashID returns the checksum type ID number.
|
||||||
|
func (e Aes256CtsHmacSha96) GetHashID() int32 {
|
||||||
|
return chksumtype.HMAC_SHA1_96_AES256
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetKeyByteSize returns the number of bytes for key of this etype.
|
||||||
|
func (e Aes256CtsHmacSha96) GetKeyByteSize() int {
|
||||||
|
return 256 / 8
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetKeySeedBitLength returns the number of bits for the seed for key generation.
|
||||||
|
func (e Aes256CtsHmacSha96) GetKeySeedBitLength() int {
|
||||||
|
return e.GetKeyByteSize() * 8
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHashFunc returns the hash function for this etype.
|
||||||
|
func (e Aes256CtsHmacSha96) GetHashFunc() func() hash.Hash {
|
||||||
|
return sha1.New
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMessageBlockByteSize returns the block size for the etype's messages.
|
||||||
|
func (e Aes256CtsHmacSha96) GetMessageBlockByteSize() int {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDefaultStringToKeyParams returns the default key derivation parameters in string form.
|
||||||
|
func (e Aes256CtsHmacSha96) GetDefaultStringToKeyParams() string {
|
||||||
|
return "00001000"
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetConfounderByteSize returns the byte count for confounder to be used during cryptographic operations.
|
||||||
|
func (e Aes256CtsHmacSha96) GetConfounderByteSize() int {
|
||||||
|
return aes.BlockSize
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHMACBitLength returns the bit count size of the integrity hash.
|
||||||
|
func (e Aes256CtsHmacSha96) GetHMACBitLength() int {
|
||||||
|
return 96
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCypherBlockBitLength returns the bit count size of the cypher block.
|
||||||
|
func (e Aes256CtsHmacSha96) GetCypherBlockBitLength() int {
|
||||||
|
return aes.BlockSize * 8
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringToKey returns a key derived from the string provided.
|
||||||
|
func (e Aes256CtsHmacSha96) StringToKey(secret string, salt string, s2kparams string) ([]byte, error) {
|
||||||
|
return rfc3962.StringToKey(secret, salt, s2kparams, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RandomToKey returns a key from the bytes provided.
|
||||||
|
func (e Aes256CtsHmacSha96) RandomToKey(b []byte) []byte {
|
||||||
|
return rfc3961.RandomToKey(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncryptData encrypts the data provided.
|
||||||
|
func (e Aes256CtsHmacSha96) EncryptData(key, data []byte) ([]byte, []byte, error) {
|
||||||
|
return rfc3962.EncryptData(key, data, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncryptMessage encrypts the message provided and concatenates it with the integrity hash to create an encrypted message.
|
||||||
|
func (e Aes256CtsHmacSha96) EncryptMessage(key, message []byte, usage uint32) ([]byte, []byte, error) {
|
||||||
|
return rfc3962.EncryptMessage(key, message, usage, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecryptData decrypts the data provided.
|
||||||
|
func (e Aes256CtsHmacSha96) DecryptData(key, data []byte) ([]byte, error) {
|
||||||
|
return rfc3962.DecryptData(key, data, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecryptMessage decrypts the message provided and verifies the integrity of the message.
|
||||||
|
func (e Aes256CtsHmacSha96) DecryptMessage(key, ciphertext []byte, usage uint32) ([]byte, error) {
|
||||||
|
return rfc3962.DecryptMessage(key, ciphertext, usage, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeriveKey derives a key from the protocol key based on the usage value.
|
||||||
|
func (e Aes256CtsHmacSha96) DeriveKey(protocolKey, usage []byte) ([]byte, error) {
|
||||||
|
return rfc3961.DeriveKey(protocolKey, usage, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeriveRandom generates data needed for key generation.
|
||||||
|
func (e Aes256CtsHmacSha96) DeriveRandom(protocolKey, usage []byte) ([]byte, error) {
|
||||||
|
return rfc3961.DeriveRandom(protocolKey, usage, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyIntegrity checks the integrity of the plaintext message.
|
||||||
|
func (e Aes256CtsHmacSha96) VerifyIntegrity(protocolKey, ct, pt []byte, usage uint32) bool {
|
||||||
|
return rfc3961.VerifyIntegrity(protocolKey, ct, pt, usage, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetChecksumHash returns a keyed checksum hash of the bytes provided.
|
||||||
|
func (e Aes256CtsHmacSha96) GetChecksumHash(protocolKey, data []byte, usage uint32) ([]byte, error) {
|
||||||
|
return common.GetHash(data, protocolKey, common.GetUsageKc(usage), e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyChecksum compares the checksum of the message bytes is the same as the checksum provided.
|
||||||
|
func (e Aes256CtsHmacSha96) VerifyChecksum(protocolKey, data, chksum []byte, usage uint32) bool {
|
||||||
|
c, err := e.GetChecksumHash(protocolKey, data, usage)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return hmac.Equal(chksum, c)
|
||||||
|
}
|
132
vendor/github.com/jcmturner/gokrb5/v8/crypto/aes256-cts-hmac-sha384-192.go
generated
vendored
Normal file
132
vendor/github.com/jcmturner/gokrb5/v8/crypto/aes256-cts-hmac-sha384-192.go
generated
vendored
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
package crypto
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/aes"
|
||||||
|
"crypto/hmac"
|
||||||
|
"crypto/sha512"
|
||||||
|
"hash"
|
||||||
|
|
||||||
|
"github.com/jcmturner/gokrb5/v8/crypto/common"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/crypto/rfc8009"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/chksumtype"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/etypeID"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RFC https://tools.ietf.org/html/rfc8009
|
||||||
|
|
||||||
|
// Aes256CtsHmacSha384192 implements Kerberos encryption type aes256-cts-hmac-sha384-192
|
||||||
|
type Aes256CtsHmacSha384192 struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetETypeID returns the EType ID number.
|
||||||
|
func (e Aes256CtsHmacSha384192) GetETypeID() int32 {
|
||||||
|
return etypeID.AES256_CTS_HMAC_SHA384_192
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHashID returns the checksum type ID number.
|
||||||
|
func (e Aes256CtsHmacSha384192) GetHashID() int32 {
|
||||||
|
return chksumtype.HMAC_SHA384_192_AES256
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetKeyByteSize returns the number of bytes for key of this etype.
|
||||||
|
func (e Aes256CtsHmacSha384192) GetKeyByteSize() int {
|
||||||
|
return 192 / 8
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetKeySeedBitLength returns the number of bits for the seed for key generation.
|
||||||
|
func (e Aes256CtsHmacSha384192) GetKeySeedBitLength() int {
|
||||||
|
return e.GetKeyByteSize() * 8
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHashFunc returns the hash function for this etype.
|
||||||
|
func (e Aes256CtsHmacSha384192) GetHashFunc() func() hash.Hash {
|
||||||
|
return sha512.New384
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMessageBlockByteSize returns the block size for the etype's messages.
|
||||||
|
func (e Aes256CtsHmacSha384192) GetMessageBlockByteSize() int {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDefaultStringToKeyParams returns the default key derivation parameters in string form.
|
||||||
|
func (e Aes256CtsHmacSha384192) GetDefaultStringToKeyParams() string {
|
||||||
|
return "00008000"
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetConfounderByteSize returns the byte count for confounder to be used during cryptographic operations.
|
||||||
|
func (e Aes256CtsHmacSha384192) GetConfounderByteSize() int {
|
||||||
|
return aes.BlockSize
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHMACBitLength returns the bit count size of the integrity hash.
|
||||||
|
func (e Aes256CtsHmacSha384192) GetHMACBitLength() int {
|
||||||
|
return 192
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCypherBlockBitLength returns the bit count size of the cypher block.
|
||||||
|
func (e Aes256CtsHmacSha384192) GetCypherBlockBitLength() int {
|
||||||
|
return aes.BlockSize * 8
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringToKey returns a key derived from the string provided.
|
||||||
|
func (e Aes256CtsHmacSha384192) StringToKey(secret string, salt string, s2kparams string) ([]byte, error) {
|
||||||
|
saltp := rfc8009.GetSaltP(salt, "aes256-cts-hmac-sha384-192")
|
||||||
|
return rfc8009.StringToKey(secret, saltp, s2kparams, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RandomToKey returns a key from the bytes provided.
|
||||||
|
func (e Aes256CtsHmacSha384192) RandomToKey(b []byte) []byte {
|
||||||
|
return rfc8009.RandomToKey(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncryptData encrypts the data provided.
|
||||||
|
func (e Aes256CtsHmacSha384192) EncryptData(key, data []byte) ([]byte, []byte, error) {
|
||||||
|
return rfc8009.EncryptData(key, data, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncryptMessage encrypts the message provided and concatenates it with the integrity hash to create an encrypted message.
|
||||||
|
func (e Aes256CtsHmacSha384192) EncryptMessage(key, message []byte, usage uint32) ([]byte, []byte, error) {
|
||||||
|
return rfc8009.EncryptMessage(key, message, usage, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecryptData decrypts the data provided.
|
||||||
|
func (e Aes256CtsHmacSha384192) DecryptData(key, data []byte) ([]byte, error) {
|
||||||
|
return rfc8009.DecryptData(key, data, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecryptMessage decrypts the message provided and verifies the integrity of the message.
|
||||||
|
func (e Aes256CtsHmacSha384192) DecryptMessage(key, ciphertext []byte, usage uint32) ([]byte, error) {
|
||||||
|
return rfc8009.DecryptMessage(key, ciphertext, usage, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeriveKey derives a key from the protocol key based on the usage value.
|
||||||
|
func (e Aes256CtsHmacSha384192) DeriveKey(protocolKey, usage []byte) ([]byte, error) {
|
||||||
|
return rfc8009.DeriveKey(protocolKey, usage, e), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeriveRandom generates data needed for key generation.
|
||||||
|
func (e Aes256CtsHmacSha384192) DeriveRandom(protocolKey, usage []byte) ([]byte, error) {
|
||||||
|
return rfc8009.DeriveRandom(protocolKey, usage, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyIntegrity checks the integrity of the ciphertext message.
|
||||||
|
// As the hash is calculated over the iv concatenated with the AES cipher output not the plaintext the pt value to this
|
||||||
|
// interface method is not use. Pass any []byte.
|
||||||
|
func (e Aes256CtsHmacSha384192) VerifyIntegrity(protocolKey, ct, pt []byte, usage uint32) bool {
|
||||||
|
// We don't need ib just there for the interface
|
||||||
|
return rfc8009.VerifyIntegrity(protocolKey, ct, usage, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetChecksumHash returns a keyed checksum hash of the bytes provided.
|
||||||
|
func (e Aes256CtsHmacSha384192) GetChecksumHash(protocolKey, data []byte, usage uint32) ([]byte, error) {
|
||||||
|
return common.GetHash(data, protocolKey, common.GetUsageKc(usage), e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyChecksum compares the checksum of the message bytes is the same as the checksum provided.
|
||||||
|
func (e Aes256CtsHmacSha384192) VerifyChecksum(protocolKey, data, chksum []byte, usage uint32) bool {
|
||||||
|
c, err := e.GetChecksumHash(protocolKey, data, usage)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return hmac.Equal(chksum, c)
|
||||||
|
}
|
132
vendor/github.com/jcmturner/gokrb5/v8/crypto/common/common.go
generated
vendored
Normal file
132
vendor/github.com/jcmturner/gokrb5/v8/crypto/common/common.go
generated
vendored
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
// Package common provides encryption methods common across encryption types
|
||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/hmac"
|
||||||
|
"encoding/binary"
|
||||||
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/jcmturner/gokrb5/v8/crypto/etype"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ZeroPad pads bytes with zeros to nearest multiple of message size m.
|
||||||
|
func ZeroPad(b []byte, m int) ([]byte, error) {
|
||||||
|
if m <= 0 {
|
||||||
|
return nil, errors.New("Invalid message block size when padding")
|
||||||
|
}
|
||||||
|
if b == nil || len(b) == 0 {
|
||||||
|
return nil, errors.New("Data not valid to pad: Zero size")
|
||||||
|
}
|
||||||
|
if l := len(b) % m; l != 0 {
|
||||||
|
n := m - l
|
||||||
|
z := make([]byte, n)
|
||||||
|
b = append(b, z...)
|
||||||
|
}
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PKCS7Pad pads bytes according to RFC 2315 to nearest multiple of message size m.
|
||||||
|
func PKCS7Pad(b []byte, m int) ([]byte, error) {
|
||||||
|
if m <= 0 {
|
||||||
|
return nil, errors.New("Invalid message block size when padding")
|
||||||
|
}
|
||||||
|
if b == nil || len(b) == 0 {
|
||||||
|
return nil, errors.New("Data not valid to pad: Zero size")
|
||||||
|
}
|
||||||
|
n := m - (len(b) % m)
|
||||||
|
pb := make([]byte, len(b)+n)
|
||||||
|
copy(pb, b)
|
||||||
|
copy(pb[len(b):], bytes.Repeat([]byte{byte(n)}, n))
|
||||||
|
return pb, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PKCS7Unpad removes RFC 2315 padding from byes where message size is m.
|
||||||
|
func PKCS7Unpad(b []byte, m int) ([]byte, error) {
|
||||||
|
if m <= 0 {
|
||||||
|
return nil, errors.New("invalid message block size when unpadding")
|
||||||
|
}
|
||||||
|
if b == nil || len(b) == 0 {
|
||||||
|
return nil, errors.New("padded data not valid: Zero size")
|
||||||
|
}
|
||||||
|
if len(b)%m != 0 {
|
||||||
|
return nil, errors.New("padded data not valid: Not multiple of message block size")
|
||||||
|
}
|
||||||
|
c := b[len(b)-1]
|
||||||
|
n := int(c)
|
||||||
|
if n == 0 || n > len(b) {
|
||||||
|
return nil, errors.New("padded data not valid: Data may not have been padded")
|
||||||
|
}
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
if b[len(b)-n+i] != c {
|
||||||
|
return nil, errors.New("padded data not valid")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return b[:len(b)-n], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHash generates the keyed hash value according to the etype's hash function.
|
||||||
|
func GetHash(pt, key []byte, usage []byte, etype etype.EType) ([]byte, error) {
|
||||||
|
k, err := etype.DeriveKey(key, usage)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to derive key for checksum: %v", err)
|
||||||
|
}
|
||||||
|
mac := hmac.New(etype.GetHashFunc(), k)
|
||||||
|
p := make([]byte, len(pt))
|
||||||
|
copy(p, pt)
|
||||||
|
mac.Write(p)
|
||||||
|
return mac.Sum(nil)[:etype.GetHMACBitLength()/8], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetChecksumHash returns a keyed checksum hash of the bytes provided.
|
||||||
|
func GetChecksumHash(b, key []byte, usage uint32, etype etype.EType) ([]byte, error) {
|
||||||
|
return GetHash(b, key, GetUsageKc(usage), etype)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetIntegrityHash returns a keyed integrity hash of the bytes provided.
|
||||||
|
func GetIntegrityHash(b, key []byte, usage uint32, etype etype.EType) ([]byte, error) {
|
||||||
|
return GetHash(b, key, GetUsageKi(usage), etype)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyChecksum compares the checksum of the msg bytes is the same as the checksum provided.
|
||||||
|
func VerifyChecksum(key, chksum, msg []byte, usage uint32, etype etype.EType) bool {
|
||||||
|
//The encrypted message is a concatenation of the encrypted output and the hash HMAC.
|
||||||
|
expectedMAC, _ := GetChecksumHash(msg, key, usage, etype)
|
||||||
|
return hmac.Equal(chksum, expectedMAC)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUsageKc returns the checksum key usage value for the usage number un.
|
||||||
|
//
|
||||||
|
// See RFC 3961 5.3 key-derivation function definition.
|
||||||
|
func GetUsageKc(un uint32) []byte {
|
||||||
|
return getUsage(un, 0x99)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUsageKe returns the encryption key usage value for the usage number un
|
||||||
|
//
|
||||||
|
// See RFC 3961 5.3 key-derivation function definition.
|
||||||
|
func GetUsageKe(un uint32) []byte {
|
||||||
|
return getUsage(un, 0xAA)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUsageKi returns the integrity key usage value for the usage number un
|
||||||
|
//
|
||||||
|
// See RFC 3961 5.3 key-derivation function definition.
|
||||||
|
func GetUsageKi(un uint32) []byte {
|
||||||
|
return getUsage(un, 0x55)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getUsage(un uint32, o byte) []byte {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
binary.Write(&buf, binary.BigEndian, un)
|
||||||
|
return append(buf.Bytes(), o)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IterationsToS2Kparams converts the number of iterations as an integer to a string representation.
|
||||||
|
func IterationsToS2Kparams(i uint32) string {
|
||||||
|
b := make([]byte, 4, 4)
|
||||||
|
binary.BigEndian.PutUint32(b, i)
|
||||||
|
return hex.EncodeToString(b)
|
||||||
|
}
|
175
vendor/github.com/jcmturner/gokrb5/v8/crypto/crypto.go
generated
vendored
Normal file
175
vendor/github.com/jcmturner/gokrb5/v8/crypto/crypto.go
generated
vendored
Normal file
|
@ -0,0 +1,175 @@
|
||||||
|
// Package crypto implements cryptographic functions for Kerberos 5 implementation.
|
||||||
|
package crypto
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/jcmturner/gokrb5/v8/crypto/etype"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/chksumtype"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/etypeID"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/patype"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetEtype returns an instances of the required etype struct for the etype ID.
|
||||||
|
func GetEtype(id int32) (etype.EType, error) {
|
||||||
|
switch id {
|
||||||
|
case etypeID.AES128_CTS_HMAC_SHA1_96:
|
||||||
|
var et Aes128CtsHmacSha96
|
||||||
|
return et, nil
|
||||||
|
case etypeID.AES256_CTS_HMAC_SHA1_96:
|
||||||
|
var et Aes256CtsHmacSha96
|
||||||
|
return et, nil
|
||||||
|
case etypeID.AES128_CTS_HMAC_SHA256_128:
|
||||||
|
var et Aes128CtsHmacSha256128
|
||||||
|
return et, nil
|
||||||
|
case etypeID.AES256_CTS_HMAC_SHA384_192:
|
||||||
|
var et Aes256CtsHmacSha384192
|
||||||
|
return et, nil
|
||||||
|
case etypeID.DES3_CBC_SHA1_KD:
|
||||||
|
var et Des3CbcSha1Kd
|
||||||
|
return et, nil
|
||||||
|
case etypeID.RC4_HMAC:
|
||||||
|
var et RC4HMAC
|
||||||
|
return et, nil
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unknown or unsupported EType: %d", id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetChksumEtype returns an instances of the required etype struct for the checksum ID.
|
||||||
|
func GetChksumEtype(id int32) (etype.EType, error) {
|
||||||
|
switch id {
|
||||||
|
case chksumtype.HMAC_SHA1_96_AES128:
|
||||||
|
var et Aes128CtsHmacSha96
|
||||||
|
return et, nil
|
||||||
|
case chksumtype.HMAC_SHA1_96_AES256:
|
||||||
|
var et Aes256CtsHmacSha96
|
||||||
|
return et, nil
|
||||||
|
case chksumtype.HMAC_SHA256_128_AES128:
|
||||||
|
var et Aes128CtsHmacSha256128
|
||||||
|
return et, nil
|
||||||
|
case chksumtype.HMAC_SHA384_192_AES256:
|
||||||
|
var et Aes256CtsHmacSha384192
|
||||||
|
return et, nil
|
||||||
|
case chksumtype.HMAC_SHA1_DES3_KD:
|
||||||
|
var et Des3CbcSha1Kd
|
||||||
|
return et, nil
|
||||||
|
case chksumtype.KERB_CHECKSUM_HMAC_MD5:
|
||||||
|
var et RC4HMAC
|
||||||
|
return et, nil
|
||||||
|
//case chksumtype.KERB_CHECKSUM_HMAC_MD5_UNSIGNED:
|
||||||
|
// var et RC4HMAC
|
||||||
|
// return et, nil
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unknown or unsupported checksum type: %d", id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetKeyFromPassword generates an encryption key from the principal's password.
|
||||||
|
func GetKeyFromPassword(passwd string, cname types.PrincipalName, realm string, etypeID int32, pas types.PADataSequence) (types.EncryptionKey, etype.EType, error) {
|
||||||
|
var key types.EncryptionKey
|
||||||
|
et, err := GetEtype(etypeID)
|
||||||
|
if err != nil {
|
||||||
|
return key, et, fmt.Errorf("error getting encryption type: %v", err)
|
||||||
|
}
|
||||||
|
sk2p := et.GetDefaultStringToKeyParams()
|
||||||
|
var salt string
|
||||||
|
var paID int32
|
||||||
|
for _, pa := range pas {
|
||||||
|
switch pa.PADataType {
|
||||||
|
case patype.PA_PW_SALT:
|
||||||
|
if paID > pa.PADataType {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
salt = string(pa.PADataValue)
|
||||||
|
case patype.PA_ETYPE_INFO:
|
||||||
|
if paID > pa.PADataType {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var eti types.ETypeInfo
|
||||||
|
err := eti.Unmarshal(pa.PADataValue)
|
||||||
|
if err != nil {
|
||||||
|
return key, et, fmt.Errorf("error unmashaling PA Data to PA-ETYPE-INFO2: %v", err)
|
||||||
|
}
|
||||||
|
if etypeID != eti[0].EType {
|
||||||
|
et, err = GetEtype(eti[0].EType)
|
||||||
|
if err != nil {
|
||||||
|
return key, et, fmt.Errorf("error getting encryption type: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
salt = string(eti[0].Salt)
|
||||||
|
case patype.PA_ETYPE_INFO2:
|
||||||
|
if paID > pa.PADataType {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var et2 types.ETypeInfo2
|
||||||
|
err := et2.Unmarshal(pa.PADataValue)
|
||||||
|
if err != nil {
|
||||||
|
return key, et, fmt.Errorf("error unmashalling PA Data to PA-ETYPE-INFO2: %v", err)
|
||||||
|
}
|
||||||
|
if etypeID != et2[0].EType {
|
||||||
|
et, err = GetEtype(et2[0].EType)
|
||||||
|
if err != nil {
|
||||||
|
return key, et, fmt.Errorf("error getting encryption type: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(et2[0].S2KParams) == 4 {
|
||||||
|
sk2p = hex.EncodeToString(et2[0].S2KParams)
|
||||||
|
}
|
||||||
|
salt = et2[0].Salt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if salt == "" {
|
||||||
|
salt = cname.GetSalt(realm)
|
||||||
|
}
|
||||||
|
k, err := et.StringToKey(passwd, salt, sk2p)
|
||||||
|
if err != nil {
|
||||||
|
return key, et, fmt.Errorf("error deriving key from string: %+v", err)
|
||||||
|
}
|
||||||
|
key = types.EncryptionKey{
|
||||||
|
KeyType: etypeID,
|
||||||
|
KeyValue: k,
|
||||||
|
}
|
||||||
|
return key, et, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetEncryptedData encrypts the data provided and returns and EncryptedData type.
|
||||||
|
// Pass a usage value of zero to use the key provided directly rather than deriving one.
|
||||||
|
func GetEncryptedData(plainBytes []byte, key types.EncryptionKey, usage uint32, kvno int) (types.EncryptedData, error) {
|
||||||
|
var ed types.EncryptedData
|
||||||
|
et, err := GetEtype(key.KeyType)
|
||||||
|
if err != nil {
|
||||||
|
return ed, fmt.Errorf("error getting etype: %v", err)
|
||||||
|
}
|
||||||
|
_, b, err := et.EncryptMessage(key.KeyValue, plainBytes, usage)
|
||||||
|
if err != nil {
|
||||||
|
return ed, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ed = types.EncryptedData{
|
||||||
|
EType: key.KeyType,
|
||||||
|
Cipher: b,
|
||||||
|
KVNO: kvno,
|
||||||
|
}
|
||||||
|
return ed, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecryptEncPart decrypts the EncryptedData.
|
||||||
|
func DecryptEncPart(ed types.EncryptedData, key types.EncryptionKey, usage uint32) ([]byte, error) {
|
||||||
|
return DecryptMessage(ed.Cipher, key, usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecryptMessage decrypts the ciphertext and verifies the integrity.
|
||||||
|
func DecryptMessage(ciphertext []byte, key types.EncryptionKey, usage uint32) ([]byte, error) {
|
||||||
|
et, err := GetEtype(key.KeyType)
|
||||||
|
if err != nil {
|
||||||
|
return []byte{}, fmt.Errorf("error decrypting: %v", err)
|
||||||
|
}
|
||||||
|
b, err := et.DecryptMessage(key.KeyValue, ciphertext, usage)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error decrypting: %v", err)
|
||||||
|
}
|
||||||
|
return b, nil
|
||||||
|
}
|
139
vendor/github.com/jcmturner/gokrb5/v8/crypto/des3-cbc-sha1-kd.go
generated
vendored
Normal file
139
vendor/github.com/jcmturner/gokrb5/v8/crypto/des3-cbc-sha1-kd.go
generated
vendored
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
package crypto
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/des"
|
||||||
|
"crypto/hmac"
|
||||||
|
"crypto/sha1"
|
||||||
|
"errors"
|
||||||
|
"hash"
|
||||||
|
|
||||||
|
"github.com/jcmturner/gokrb5/v8/crypto/common"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/crypto/rfc3961"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/chksumtype"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/etypeID"
|
||||||
|
)
|
||||||
|
|
||||||
|
//RFC: 3961 Section 6.3
|
||||||
|
|
||||||
|
// Des3CbcSha1Kd implements Kerberos encryption type des3-cbc-hmac-sha1-kd
|
||||||
|
type Des3CbcSha1Kd struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetETypeID returns the EType ID number.
|
||||||
|
func (e Des3CbcSha1Kd) GetETypeID() int32 {
|
||||||
|
return etypeID.DES3_CBC_SHA1_KD
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHashID returns the checksum type ID number.
|
||||||
|
func (e Des3CbcSha1Kd) GetHashID() int32 {
|
||||||
|
return chksumtype.HMAC_SHA1_DES3_KD
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetKeyByteSize returns the number of bytes for key of this etype.
|
||||||
|
func (e Des3CbcSha1Kd) GetKeyByteSize() int {
|
||||||
|
return 24
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetKeySeedBitLength returns the number of bits for the seed for key generation.
|
||||||
|
func (e Des3CbcSha1Kd) GetKeySeedBitLength() int {
|
||||||
|
return 21 * 8
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHashFunc returns the hash function for this etype.
|
||||||
|
func (e Des3CbcSha1Kd) GetHashFunc() func() hash.Hash {
|
||||||
|
return sha1.New
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMessageBlockByteSize returns the block size for the etype's messages.
|
||||||
|
func (e Des3CbcSha1Kd) GetMessageBlockByteSize() int {
|
||||||
|
//For traditional CBC mode with padding, it would be the underlying cipher's block size
|
||||||
|
return des.BlockSize
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDefaultStringToKeyParams returns the default key derivation parameters in string form.
|
||||||
|
func (e Des3CbcSha1Kd) GetDefaultStringToKeyParams() string {
|
||||||
|
var s string
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetConfounderByteSize returns the byte count for confounder to be used during cryptographic operations.
|
||||||
|
func (e Des3CbcSha1Kd) GetConfounderByteSize() int {
|
||||||
|
return des.BlockSize
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHMACBitLength returns the bit count size of the integrity hash.
|
||||||
|
func (e Des3CbcSha1Kd) GetHMACBitLength() int {
|
||||||
|
return e.GetHashFunc()().Size() * 8
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCypherBlockBitLength returns the bit count size of the cypher block.
|
||||||
|
func (e Des3CbcSha1Kd) GetCypherBlockBitLength() int {
|
||||||
|
return des.BlockSize * 8
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringToKey returns a key derived from the string provided.
|
||||||
|
func (e Des3CbcSha1Kd) StringToKey(secret string, salt string, s2kparams string) ([]byte, error) {
|
||||||
|
if s2kparams != "" {
|
||||||
|
return []byte{}, errors.New("s2kparams must be an empty string")
|
||||||
|
}
|
||||||
|
return rfc3961.DES3StringToKey(secret, salt, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RandomToKey returns a key from the bytes provided.
|
||||||
|
func (e Des3CbcSha1Kd) RandomToKey(b []byte) []byte {
|
||||||
|
return rfc3961.DES3RandomToKey(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeriveRandom generates data needed for key generation.
|
||||||
|
func (e Des3CbcSha1Kd) DeriveRandom(protocolKey, usage []byte) ([]byte, error) {
|
||||||
|
r, err := rfc3961.DeriveRandom(protocolKey, usage, e)
|
||||||
|
return r, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeriveKey derives a key from the protocol key based on the usage value.
|
||||||
|
func (e Des3CbcSha1Kd) DeriveKey(protocolKey, usage []byte) ([]byte, error) {
|
||||||
|
r, err := e.DeriveRandom(protocolKey, usage)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return e.RandomToKey(r), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncryptData encrypts the data provided.
|
||||||
|
func (e Des3CbcSha1Kd) EncryptData(key, data []byte) ([]byte, []byte, error) {
|
||||||
|
return rfc3961.DES3EncryptData(key, data, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncryptMessage encrypts the message provided and concatenates it with the integrity hash to create an encrypted message.
|
||||||
|
func (e Des3CbcSha1Kd) EncryptMessage(key, message []byte, usage uint32) ([]byte, []byte, error) {
|
||||||
|
return rfc3961.DES3EncryptMessage(key, message, usage, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecryptData decrypts the data provided.
|
||||||
|
func (e Des3CbcSha1Kd) DecryptData(key, data []byte) ([]byte, error) {
|
||||||
|
return rfc3961.DES3DecryptData(key, data, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecryptMessage decrypts the message provided and verifies the integrity of the message.
|
||||||
|
func (e Des3CbcSha1Kd) DecryptMessage(key, ciphertext []byte, usage uint32) ([]byte, error) {
|
||||||
|
return rfc3961.DES3DecryptMessage(key, ciphertext, usage, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyIntegrity checks the integrity of the plaintext message.
|
||||||
|
func (e Des3CbcSha1Kd) VerifyIntegrity(protocolKey, ct, pt []byte, usage uint32) bool {
|
||||||
|
return rfc3961.VerifyIntegrity(protocolKey, ct, pt, usage, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetChecksumHash returns a keyed checksum hash of the bytes provided.
|
||||||
|
func (e Des3CbcSha1Kd) GetChecksumHash(protocolKey, data []byte, usage uint32) ([]byte, error) {
|
||||||
|
return common.GetHash(data, protocolKey, common.GetUsageKc(usage), e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyChecksum compares the checksum of the message bytes is the same as the checksum provided.
|
||||||
|
func (e Des3CbcSha1Kd) VerifyChecksum(protocolKey, data, chksum []byte, usage uint32) bool {
|
||||||
|
c, err := e.GetChecksumHash(protocolKey, data, usage)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return hmac.Equal(chksum, c)
|
||||||
|
}
|
29
vendor/github.com/jcmturner/gokrb5/v8/crypto/etype/etype.go
generated
vendored
Normal file
29
vendor/github.com/jcmturner/gokrb5/v8/crypto/etype/etype.go
generated
vendored
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
// Package etype provides the Kerberos Encryption Type interface
|
||||||
|
package etype
|
||||||
|
|
||||||
|
import "hash"
|
||||||
|
|
||||||
|
// EType is the interface defining the Encryption Type.
|
||||||
|
type EType interface {
|
||||||
|
GetETypeID() int32
|
||||||
|
GetHashID() int32
|
||||||
|
GetKeyByteSize() int
|
||||||
|
GetKeySeedBitLength() int
|
||||||
|
GetDefaultStringToKeyParams() string
|
||||||
|
StringToKey(string, salt, s2kparams string) ([]byte, error)
|
||||||
|
RandomToKey(b []byte) []byte
|
||||||
|
GetHMACBitLength() int
|
||||||
|
GetMessageBlockByteSize() int
|
||||||
|
EncryptData(key, data []byte) ([]byte, []byte, error)
|
||||||
|
EncryptMessage(key, message []byte, usage uint32) ([]byte, []byte, error)
|
||||||
|
DecryptData(key, data []byte) ([]byte, error)
|
||||||
|
DecryptMessage(key, ciphertext []byte, usage uint32) ([]byte, error)
|
||||||
|
GetCypherBlockBitLength() int
|
||||||
|
GetConfounderByteSize() int
|
||||||
|
DeriveKey(protocolKey, usage []byte) ([]byte, error)
|
||||||
|
DeriveRandom(protocolKey, usage []byte) ([]byte, error)
|
||||||
|
VerifyIntegrity(protocolKey, ct, pt []byte, usage uint32) bool
|
||||||
|
GetChecksumHash(protocolKey, data []byte, usage uint32) ([]byte, error)
|
||||||
|
VerifyChecksum(protocolKey, data, chksum []byte, usage uint32) bool
|
||||||
|
GetHashFunc() func() hash.Hash
|
||||||
|
}
|
133
vendor/github.com/jcmturner/gokrb5/v8/crypto/rc4-hmac.go
generated
vendored
Normal file
133
vendor/github.com/jcmturner/gokrb5/v8/crypto/rc4-hmac.go
generated
vendored
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
package crypto
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/hmac"
|
||||||
|
"crypto/md5"
|
||||||
|
"hash"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/jcmturner/gokrb5/v8/crypto/rfc3961"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/crypto/rfc4757"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/chksumtype"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/etypeID"
|
||||||
|
"golang.org/x/crypto/md4"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RC4HMAC implements Kerberos encryption type rc4-hmac
|
||||||
|
type RC4HMAC struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetETypeID returns the EType ID number.
|
||||||
|
func (e RC4HMAC) GetETypeID() int32 {
|
||||||
|
return etypeID.RC4_HMAC
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHashID returns the checksum type ID number.
|
||||||
|
func (e RC4HMAC) GetHashID() int32 {
|
||||||
|
return chksumtype.KERB_CHECKSUM_HMAC_MD5
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetKeyByteSize returns the number of bytes for key of this etype.
|
||||||
|
func (e RC4HMAC) GetKeyByteSize() int {
|
||||||
|
return 16
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetKeySeedBitLength returns the number of bits for the seed for key generation.
|
||||||
|
func (e RC4HMAC) GetKeySeedBitLength() int {
|
||||||
|
return e.GetKeyByteSize() * 8
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHashFunc returns the hash function for this etype.
|
||||||
|
func (e RC4HMAC) GetHashFunc() func() hash.Hash {
|
||||||
|
return md5.New
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMessageBlockByteSize returns the block size for the etype's messages.
|
||||||
|
func (e RC4HMAC) GetMessageBlockByteSize() int {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDefaultStringToKeyParams returns the default key derivation parameters in string form.
|
||||||
|
func (e RC4HMAC) GetDefaultStringToKeyParams() string {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetConfounderByteSize returns the byte count for confounder to be used during cryptographic operations.
|
||||||
|
func (e RC4HMAC) GetConfounderByteSize() int {
|
||||||
|
return 8
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHMACBitLength returns the bit count size of the integrity hash.
|
||||||
|
func (e RC4HMAC) GetHMACBitLength() int {
|
||||||
|
return md5.Size * 8
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCypherBlockBitLength returns the bit count size of the cypher block.
|
||||||
|
func (e RC4HMAC) GetCypherBlockBitLength() int {
|
||||||
|
return 8 // doesn't really apply
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringToKey returns a key derived from the string provided.
|
||||||
|
func (e RC4HMAC) StringToKey(secret string, salt string, s2kparams string) ([]byte, error) {
|
||||||
|
return rfc4757.StringToKey(secret)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RandomToKey returns a key from the bytes provided.
|
||||||
|
func (e RC4HMAC) RandomToKey(b []byte) []byte {
|
||||||
|
r := bytes.NewReader(b)
|
||||||
|
h := md4.New()
|
||||||
|
io.Copy(h, r)
|
||||||
|
return h.Sum(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncryptData encrypts the data provided.
|
||||||
|
func (e RC4HMAC) EncryptData(key, data []byte) ([]byte, []byte, error) {
|
||||||
|
b, err := rfc4757.EncryptData(key, data, e)
|
||||||
|
return []byte{}, b, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncryptMessage encrypts the message provided and concatenates it with the integrity hash to create an encrypted message.
|
||||||
|
func (e RC4HMAC) EncryptMessage(key, message []byte, usage uint32) ([]byte, []byte, error) {
|
||||||
|
b, err := rfc4757.EncryptMessage(key, message, usage, false, e)
|
||||||
|
return []byte{}, b, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecryptData decrypts the data provided.
|
||||||
|
func (e RC4HMAC) DecryptData(key, data []byte) ([]byte, error) {
|
||||||
|
return rfc4757.DecryptData(key, data, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecryptMessage decrypts the message provided and verifies the integrity of the message.
|
||||||
|
func (e RC4HMAC) DecryptMessage(key, ciphertext []byte, usage uint32) ([]byte, error) {
|
||||||
|
return rfc4757.DecryptMessage(key, ciphertext, usage, false, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeriveKey derives a key from the protocol key based on the usage value.
|
||||||
|
func (e RC4HMAC) DeriveKey(protocolKey, usage []byte) ([]byte, error) {
|
||||||
|
return rfc4757.HMAC(protocolKey, usage), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeriveRandom generates data needed for key generation.
|
||||||
|
func (e RC4HMAC) DeriveRandom(protocolKey, usage []byte) ([]byte, error) {
|
||||||
|
return rfc3961.DeriveRandom(protocolKey, usage, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyIntegrity checks the integrity of the plaintext message.
|
||||||
|
func (e RC4HMAC) VerifyIntegrity(protocolKey, ct, pt []byte, usage uint32) bool {
|
||||||
|
return rfc4757.VerifyIntegrity(protocolKey, pt, ct, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetChecksumHash returns a keyed checksum hash of the bytes provided.
|
||||||
|
func (e RC4HMAC) GetChecksumHash(protocolKey, data []byte, usage uint32) ([]byte, error) {
|
||||||
|
return rfc4757.Checksum(protocolKey, usage, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyChecksum compares the checksum of the message bytes is the same as the checksum provided.
|
||||||
|
func (e RC4HMAC) VerifyChecksum(protocolKey, data, chksum []byte, usage uint32) bool {
|
||||||
|
checksum, err := rfc4757.Checksum(protocolKey, usage, data)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return hmac.Equal(checksum, chksum)
|
||||||
|
}
|
119
vendor/github.com/jcmturner/gokrb5/v8/crypto/rfc3961/encryption.go
generated
vendored
Normal file
119
vendor/github.com/jcmturner/gokrb5/v8/crypto/rfc3961/encryption.go
generated
vendored
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
// Package rfc3961 provides encryption and checksum methods as specified in RFC 3961
|
||||||
|
package rfc3961
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/cipher"
|
||||||
|
"crypto/des"
|
||||||
|
"crypto/hmac"
|
||||||
|
"crypto/rand"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/jcmturner/gokrb5/v8/crypto/common"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/crypto/etype"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DES3EncryptData encrypts the data provided using DES3 and methods specific to the etype provided.
|
||||||
|
func DES3EncryptData(key, data []byte, e etype.EType) ([]byte, []byte, error) {
|
||||||
|
if len(key) != e.GetKeyByteSize() {
|
||||||
|
return nil, nil, fmt.Errorf("incorrect keysize: expected: %v actual: %v", e.GetKeyByteSize(), len(key))
|
||||||
|
}
|
||||||
|
data, _ = common.ZeroPad(data, e.GetMessageBlockByteSize())
|
||||||
|
|
||||||
|
block, err := des.NewTripleDESCipher(key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("error creating cipher: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
//RFC 3961: initial cipher state All bits zero
|
||||||
|
ivz := make([]byte, des.BlockSize)
|
||||||
|
|
||||||
|
ct := make([]byte, len(data))
|
||||||
|
mode := cipher.NewCBCEncrypter(block, ivz)
|
||||||
|
mode.CryptBlocks(ct, data)
|
||||||
|
return ct[len(ct)-e.GetMessageBlockByteSize():], ct, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DES3EncryptMessage encrypts the message provided using DES3 and methods specific to the etype provided.
|
||||||
|
// The encrypted data is concatenated with its integrity hash to create an encrypted message.
|
||||||
|
func DES3EncryptMessage(key, message []byte, usage uint32, e etype.EType) ([]byte, []byte, error) {
|
||||||
|
//confounder
|
||||||
|
c := make([]byte, e.GetConfounderByteSize())
|
||||||
|
_, err := rand.Read(c)
|
||||||
|
if err != nil {
|
||||||
|
return []byte{}, []byte{}, fmt.Errorf("could not generate random confounder: %v", err)
|
||||||
|
}
|
||||||
|
plainBytes := append(c, message...)
|
||||||
|
plainBytes, _ = common.ZeroPad(plainBytes, e.GetMessageBlockByteSize())
|
||||||
|
|
||||||
|
// Derive key for encryption from usage
|
||||||
|
var k []byte
|
||||||
|
if usage != 0 {
|
||||||
|
k, err = e.DeriveKey(key, common.GetUsageKe(usage))
|
||||||
|
if err != nil {
|
||||||
|
return []byte{}, []byte{}, fmt.Errorf("error deriving key for encryption: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
iv, b, err := e.EncryptData(k, plainBytes)
|
||||||
|
if err != nil {
|
||||||
|
return iv, b, fmt.Errorf("error encrypting data: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate and append integrity hash
|
||||||
|
ih, err := common.GetIntegrityHash(plainBytes, key, usage, e)
|
||||||
|
if err != nil {
|
||||||
|
return iv, b, fmt.Errorf("error encrypting data: %v", err)
|
||||||
|
}
|
||||||
|
b = append(b, ih...)
|
||||||
|
return iv, b, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DES3DecryptData decrypts the data provided using DES3 and methods specific to the etype provided.
|
||||||
|
func DES3DecryptData(key, data []byte, e etype.EType) ([]byte, error) {
|
||||||
|
if len(key) != e.GetKeyByteSize() {
|
||||||
|
return []byte{}, fmt.Errorf("incorrect keysize: expected: %v actual: %v", e.GetKeyByteSize(), len(key))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(data) < des.BlockSize || len(data)%des.BlockSize != 0 {
|
||||||
|
return []byte{}, errors.New("ciphertext is not a multiple of the block size")
|
||||||
|
}
|
||||||
|
block, err := des.NewTripleDESCipher(key)
|
||||||
|
if err != nil {
|
||||||
|
return []byte{}, fmt.Errorf("error creating cipher: %v", err)
|
||||||
|
}
|
||||||
|
pt := make([]byte, len(data))
|
||||||
|
ivz := make([]byte, des.BlockSize)
|
||||||
|
mode := cipher.NewCBCDecrypter(block, ivz)
|
||||||
|
mode.CryptBlocks(pt, data)
|
||||||
|
return pt, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DES3DecryptMessage decrypts the message provided using DES3 and methods specific to the etype provided.
|
||||||
|
// The integrity of the message is also verified.
|
||||||
|
func DES3DecryptMessage(key, ciphertext []byte, usage uint32, e etype.EType) ([]byte, error) {
|
||||||
|
//Derive the key
|
||||||
|
k, err := e.DeriveKey(key, common.GetUsageKe(usage))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error deriving key: %v", err)
|
||||||
|
}
|
||||||
|
// Strip off the checksum from the end
|
||||||
|
b, err := e.DecryptData(k, ciphertext[:len(ciphertext)-e.GetHMACBitLength()/8])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error decrypting: %v", err)
|
||||||
|
}
|
||||||
|
//Verify checksum
|
||||||
|
if !e.VerifyIntegrity(key, ciphertext, b, usage) {
|
||||||
|
return nil, errors.New("error decrypting: integrity verification failed")
|
||||||
|
}
|
||||||
|
//Remove the confounder bytes
|
||||||
|
return b[e.GetConfounderByteSize():], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyIntegrity verifies the integrity of cipertext bytes ct.
|
||||||
|
func VerifyIntegrity(key, ct, pt []byte, usage uint32, etype etype.EType) bool {
|
||||||
|
h := make([]byte, etype.GetHMACBitLength()/8)
|
||||||
|
copy(h, ct[len(ct)-etype.GetHMACBitLength()/8:])
|
||||||
|
expectedMAC, _ := common.GetIntegrityHash(pt, key, usage, etype)
|
||||||
|
return hmac.Equal(h, expectedMAC)
|
||||||
|
}
|
169
vendor/github.com/jcmturner/gokrb5/v8/crypto/rfc3961/keyDerivation.go
generated
vendored
Normal file
169
vendor/github.com/jcmturner/gokrb5/v8/crypto/rfc3961/keyDerivation.go
generated
vendored
Normal file
|
@ -0,0 +1,169 @@
|
||||||
|
package rfc3961
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
|
||||||
|
"github.com/jcmturner/gokrb5/v8/crypto/etype"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
prfconstant = "prf"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DeriveRandom implements the RFC 3961 defined function: DR(Key, Constant) = k-truncate(E(Key, Constant, initial-cipher-state)).
|
||||||
|
//
|
||||||
|
// key: base key or protocol key. Likely to be a key from a keytab file.
|
||||||
|
//
|
||||||
|
// usage: a constant.
|
||||||
|
//
|
||||||
|
// n: block size in bits (not bytes) - note if you use something like aes.BlockSize this is in bytes.
|
||||||
|
//
|
||||||
|
// k: key length / key seed length in bits. Eg. for AES256 this value is 256.
|
||||||
|
//
|
||||||
|
// e: the encryption etype function to use.
|
||||||
|
func DeriveRandom(key, usage []byte, e etype.EType) ([]byte, error) {
|
||||||
|
n := e.GetCypherBlockBitLength()
|
||||||
|
k := e.GetKeySeedBitLength()
|
||||||
|
//Ensure the usage constant is at least the size of the cypher block size. Pass it through the nfold algorithm that will "stretch" it if needs be.
|
||||||
|
nFoldUsage := Nfold(usage, n)
|
||||||
|
//k-truncate implemented by creating a byte array the size of k (k is in bits hence /8)
|
||||||
|
out := make([]byte, k/8)
|
||||||
|
// Keep feeding the output back into the encryption function until it is no longer short than k.
|
||||||
|
_, K, err := e.EncryptData(key, nFoldUsage)
|
||||||
|
if err != nil {
|
||||||
|
return out, err
|
||||||
|
}
|
||||||
|
for i := copy(out, K); i < len(out); {
|
||||||
|
_, K, _ = e.EncryptData(key, K)
|
||||||
|
i = i + copy(out[i:], K)
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeriveKey derives a key from the protocol key based on the usage and the etype's specific methods.
|
||||||
|
func DeriveKey(protocolKey, usage []byte, e etype.EType) ([]byte, error) {
|
||||||
|
r, err := e.DeriveRandom(protocolKey, usage)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return e.RandomToKey(r), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RandomToKey returns a key from the bytes provided according to the definition in RFC 3961.
|
||||||
|
func RandomToKey(b []byte) []byte {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// DES3RandomToKey returns a key from the bytes provided according to the definition in RFC 3961 for DES3 etypes.
|
||||||
|
func DES3RandomToKey(b []byte) []byte {
|
||||||
|
r := fixWeakKey(stretch56Bits(b[:7]))
|
||||||
|
r2 := fixWeakKey(stretch56Bits(b[7:14]))
|
||||||
|
r = append(r, r2...)
|
||||||
|
r3 := fixWeakKey(stretch56Bits(b[14:21]))
|
||||||
|
r = append(r, r3...)
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// DES3StringToKey returns a key derived from the string provided according to the definition in RFC 3961 for DES3 etypes.
|
||||||
|
func DES3StringToKey(secret, salt string, e etype.EType) ([]byte, error) {
|
||||||
|
s := secret + salt
|
||||||
|
tkey := e.RandomToKey(Nfold([]byte(s), e.GetKeySeedBitLength()))
|
||||||
|
return e.DeriveKey(tkey, []byte("kerberos"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// PseudoRandom function as defined in RFC 3961
|
||||||
|
func PseudoRandom(key, b []byte, e etype.EType) ([]byte, error) {
|
||||||
|
h := e.GetHashFunc()()
|
||||||
|
h.Write(b)
|
||||||
|
tmp := h.Sum(nil)[:e.GetMessageBlockByteSize()]
|
||||||
|
k, err := e.DeriveKey(key, []byte(prfconstant))
|
||||||
|
if err != nil {
|
||||||
|
return []byte{}, err
|
||||||
|
}
|
||||||
|
_, prf, err := e.EncryptData(k, tmp)
|
||||||
|
if err != nil {
|
||||||
|
return []byte{}, err
|
||||||
|
}
|
||||||
|
return prf, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func stretch56Bits(b []byte) []byte {
|
||||||
|
d := make([]byte, len(b), len(b))
|
||||||
|
copy(d, b)
|
||||||
|
var lb byte
|
||||||
|
for i, v := range d {
|
||||||
|
bv, nb := calcEvenParity(v)
|
||||||
|
d[i] = nb
|
||||||
|
if bv != 0 {
|
||||||
|
lb = lb | (1 << uint(i+1))
|
||||||
|
} else {
|
||||||
|
lb = lb &^ (1 << uint(i+1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_, lb = calcEvenParity(lb)
|
||||||
|
d = append(d, lb)
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
func calcEvenParity(b byte) (uint8, uint8) {
|
||||||
|
lowestbit := b & 0x01
|
||||||
|
// c counter of 1s in the first 7 bits of the byte
|
||||||
|
var c int
|
||||||
|
// Iterate over the highest 7 bits (hence p starts at 1 not zero) and count the 1s.
|
||||||
|
for p := 1; p < 8; p++ {
|
||||||
|
v := b & (1 << uint(p))
|
||||||
|
if v != 0 {
|
||||||
|
c++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if c%2 == 0 {
|
||||||
|
//Even number of 1s so set parity to 1
|
||||||
|
b = b | 1
|
||||||
|
} else {
|
||||||
|
//Odd number of 1s so set parity to 0
|
||||||
|
b = b &^ 1
|
||||||
|
}
|
||||||
|
return lowestbit, b
|
||||||
|
}
|
||||||
|
|
||||||
|
func fixWeakKey(b []byte) []byte {
|
||||||
|
if weak(b) {
|
||||||
|
b[7] ^= 0xF0
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func weak(b []byte) bool {
|
||||||
|
// weak keys from https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-67r1.pdf
|
||||||
|
weakKeys := [4][]byte{
|
||||||
|
{0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
|
||||||
|
{0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE},
|
||||||
|
{0xE0, 0xE0, 0xE0, 0xE0, 0xF1, 0xF1, 0xF1, 0xF1},
|
||||||
|
{0x1F, 0x1F, 0x1F, 0x1F, 0x0E, 0x0E, 0x0E, 0x0E},
|
||||||
|
}
|
||||||
|
semiWeakKeys := [12][]byte{
|
||||||
|
{0x01, 0x1F, 0x01, 0x1F, 0x01, 0x0E, 0x01, 0x0E},
|
||||||
|
{0x1F, 0x01, 0x1F, 0x01, 0x0E, 0x01, 0x0E, 0x01},
|
||||||
|
{0x01, 0xE0, 0x01, 0xE0, 0x01, 0xF1, 0x01, 0xF1},
|
||||||
|
{0xE0, 0x01, 0xE0, 0x01, 0xF1, 0x01, 0xF1, 0x01},
|
||||||
|
{0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE},
|
||||||
|
{0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01},
|
||||||
|
{0x1F, 0xE0, 0x1F, 0xE0, 0x0E, 0xF1, 0x0E, 0xF1},
|
||||||
|
{0xE0, 0x1F, 0xE0, 0x1F, 0xF1, 0x0E, 0xF1, 0x0E},
|
||||||
|
{0x1F, 0xFE, 0x1F, 0xFE, 0x0E, 0xFE, 0x0E, 0xFE},
|
||||||
|
{0xFE, 0x1F, 0xFE, 0x1F, 0xFE, 0x0E, 0xFE, 0x0E},
|
||||||
|
{0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1, 0xFE},
|
||||||
|
{0xFE, 0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1},
|
||||||
|
}
|
||||||
|
for _, k := range weakKeys {
|
||||||
|
if bytes.Equal(b, k) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, k := range semiWeakKeys {
|
||||||
|
if bytes.Equal(b, k) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
107
vendor/github.com/jcmturner/gokrb5/v8/crypto/rfc3961/nfold.go
generated
vendored
Normal file
107
vendor/github.com/jcmturner/gokrb5/v8/crypto/rfc3961/nfold.go
generated
vendored
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
package rfc3961
|
||||||
|
|
||||||
|
// Implementation of the n-fold algorithm as defined in RFC 3961.
|
||||||
|
|
||||||
|
/* Credits
|
||||||
|
This golang implementation of nfold used the following project for help with implementation detail.
|
||||||
|
Although their source is in java it was helpful as a reference implementation of the RFC.
|
||||||
|
You can find the source code of their open source project along with license information below.
|
||||||
|
We acknowledge and are grateful to these developers for their contributions to open source
|
||||||
|
|
||||||
|
Project: Apache Directory (http://http://directory.apache.org/)
|
||||||
|
https://svn.apache.org/repos/asf/directory/apacheds/tags/1.5.1/kerberos-shared/src/main/java/org/apache/directory/server/kerberos/shared/crypto/encryption/NFold.java
|
||||||
|
License: http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Nfold expands the key to ensure it is not smaller than one cipher block.
|
||||||
|
// Defined in RFC 3961.
|
||||||
|
//
|
||||||
|
// m input bytes that will be "stretched" to the least common multiple of n bits and the bit length of m.
|
||||||
|
func Nfold(m []byte, n int) []byte {
|
||||||
|
k := len(m) * 8
|
||||||
|
|
||||||
|
//Get the lowest common multiple of the two bit sizes
|
||||||
|
lcm := lcm(n, k)
|
||||||
|
relicate := lcm / k
|
||||||
|
var sumBytes []byte
|
||||||
|
|
||||||
|
for i := 0; i < relicate; i++ {
|
||||||
|
rotation := 13 * i
|
||||||
|
sumBytes = append(sumBytes, rotateRight(m, rotation)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
nfold := make([]byte, n/8)
|
||||||
|
sum := make([]byte, n/8)
|
||||||
|
for i := 0; i < lcm/n; i++ {
|
||||||
|
for j := 0; j < n/8; j++ {
|
||||||
|
sum[j] = sumBytes[j+(i*len(sum))]
|
||||||
|
}
|
||||||
|
nfold = onesComplementAddition(nfold, sum)
|
||||||
|
}
|
||||||
|
return nfold
|
||||||
|
}
|
||||||
|
|
||||||
|
func onesComplementAddition(n1, n2 []byte) []byte {
|
||||||
|
numBits := len(n1) * 8
|
||||||
|
out := make([]byte, numBits/8)
|
||||||
|
carry := 0
|
||||||
|
for i := numBits - 1; i > -1; i-- {
|
||||||
|
n1b := getBit(&n1, i)
|
||||||
|
n2b := getBit(&n2, i)
|
||||||
|
s := n1b + n2b + carry
|
||||||
|
|
||||||
|
if s == 0 || s == 1 {
|
||||||
|
setBit(&out, i, s)
|
||||||
|
carry = 0
|
||||||
|
} else if s == 2 {
|
||||||
|
carry = 1
|
||||||
|
} else if s == 3 {
|
||||||
|
setBit(&out, i, 1)
|
||||||
|
carry = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if carry == 1 {
|
||||||
|
carryArray := make([]byte, len(n1))
|
||||||
|
carryArray[len(carryArray)-1] = 1
|
||||||
|
out = onesComplementAddition(out, carryArray)
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func rotateRight(b []byte, step int) []byte {
|
||||||
|
out := make([]byte, len(b))
|
||||||
|
bitLen := len(b) * 8
|
||||||
|
for i := 0; i < bitLen; i++ {
|
||||||
|
v := getBit(&b, i)
|
||||||
|
setBit(&out, (i+step)%bitLen, v)
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func lcm(x, y int) int {
|
||||||
|
return (x * y) / gcd(x, y)
|
||||||
|
}
|
||||||
|
|
||||||
|
func gcd(x, y int) int {
|
||||||
|
for y != 0 {
|
||||||
|
x, y = y, x%y
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
func getBit(b *[]byte, p int) int {
|
||||||
|
pByte := p / 8
|
||||||
|
pBit := uint(p % 8)
|
||||||
|
vByte := (*b)[pByte]
|
||||||
|
vInt := int(vByte >> (8 - (pBit + 1)) & 0x0001)
|
||||||
|
return vInt
|
||||||
|
}
|
||||||
|
|
||||||
|
func setBit(b *[]byte, p, v int) {
|
||||||
|
pByte := p / 8
|
||||||
|
pBit := uint(p % 8)
|
||||||
|
oldByte := (*b)[pByte]
|
||||||
|
var newByte byte
|
||||||
|
newByte = byte(v<<(8-(pBit+1))) | oldByte
|
||||||
|
(*b)[pByte] = newByte
|
||||||
|
}
|
89
vendor/github.com/jcmturner/gokrb5/v8/crypto/rfc3962/encryption.go
generated
vendored
Normal file
89
vendor/github.com/jcmturner/gokrb5/v8/crypto/rfc3962/encryption.go
generated
vendored
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
// Package rfc3962 provides encryption and checksum methods as specified in RFC 3962
|
||||||
|
package rfc3962
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/jcmturner/aescts/v2"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/crypto/common"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/crypto/etype"
|
||||||
|
)
|
||||||
|
|
||||||
|
// EncryptData encrypts the data provided using methods specific to the etype provided as defined in RFC 3962.
|
||||||
|
func EncryptData(key, data []byte, e etype.EType) ([]byte, []byte, error) {
|
||||||
|
if len(key) != e.GetKeyByteSize() {
|
||||||
|
return []byte{}, []byte{}, fmt.Errorf("incorrect keysize: expected: %v actual: %v", e.GetKeyByteSize(), len(key))
|
||||||
|
}
|
||||||
|
ivz := make([]byte, e.GetCypherBlockBitLength()/8)
|
||||||
|
return aescts.Encrypt(key, ivz, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncryptMessage encrypts the message provided using the methods specific to the etype provided as defined in RFC 3962.
|
||||||
|
// The encrypted data is concatenated with its integrity hash to create an encrypted message.
|
||||||
|
func EncryptMessage(key, message []byte, usage uint32, e etype.EType) ([]byte, []byte, error) {
|
||||||
|
if len(key) != e.GetKeyByteSize() {
|
||||||
|
return []byte{}, []byte{}, fmt.Errorf("incorrect keysize: expected: %v actual: %v", e.GetKeyByteSize(), len(key))
|
||||||
|
}
|
||||||
|
//confounder
|
||||||
|
c := make([]byte, e.GetConfounderByteSize())
|
||||||
|
_, err := rand.Read(c)
|
||||||
|
if err != nil {
|
||||||
|
return []byte{}, []byte{}, fmt.Errorf("could not generate random confounder: %v", err)
|
||||||
|
}
|
||||||
|
plainBytes := append(c, message...)
|
||||||
|
|
||||||
|
// Derive key for encryption from usage
|
||||||
|
var k []byte
|
||||||
|
if usage != 0 {
|
||||||
|
k, err = e.DeriveKey(key, common.GetUsageKe(usage))
|
||||||
|
if err != nil {
|
||||||
|
return []byte{}, []byte{}, fmt.Errorf("error deriving key for encryption: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encrypt the data
|
||||||
|
iv, b, err := e.EncryptData(k, plainBytes)
|
||||||
|
if err != nil {
|
||||||
|
return iv, b, fmt.Errorf("error encrypting data: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate and append integrity hash
|
||||||
|
ih, err := common.GetIntegrityHash(plainBytes, key, usage, e)
|
||||||
|
if err != nil {
|
||||||
|
return iv, b, fmt.Errorf("error encrypting data: %v", err)
|
||||||
|
}
|
||||||
|
b = append(b, ih...)
|
||||||
|
return iv, b, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecryptData decrypts the data provided using the methods specific to the etype provided as defined in RFC 3962.
|
||||||
|
func DecryptData(key, data []byte, e etype.EType) ([]byte, error) {
|
||||||
|
if len(key) != e.GetKeyByteSize() {
|
||||||
|
return []byte{}, fmt.Errorf("incorrect keysize: expected: %v actual: %v", e.GetKeyByteSize(), len(key))
|
||||||
|
}
|
||||||
|
ivz := make([]byte, e.GetCypherBlockBitLength()/8)
|
||||||
|
return aescts.Decrypt(key, ivz, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecryptMessage decrypts the message provided using the methods specific to the etype provided as defined in RFC 3962.
|
||||||
|
// The integrity of the message is also verified.
|
||||||
|
func DecryptMessage(key, ciphertext []byte, usage uint32, e etype.EType) ([]byte, error) {
|
||||||
|
//Derive the key
|
||||||
|
k, err := e.DeriveKey(key, common.GetUsageKe(usage))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error deriving key: %v", err)
|
||||||
|
}
|
||||||
|
// Strip off the checksum from the end
|
||||||
|
b, err := e.DecryptData(k, ciphertext[:len(ciphertext)-e.GetHMACBitLength()/8])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
//Verify checksum
|
||||||
|
if !e.VerifyIntegrity(key, ciphertext, b, usage) {
|
||||||
|
return nil, errors.New("integrity verification failed")
|
||||||
|
}
|
||||||
|
//Remove the confounder bytes
|
||||||
|
return b[e.GetConfounderByteSize():], nil
|
||||||
|
}
|
51
vendor/github.com/jcmturner/gokrb5/v8/crypto/rfc3962/keyDerivation.go
generated
vendored
Normal file
51
vendor/github.com/jcmturner/gokrb5/v8/crypto/rfc3962/keyDerivation.go
generated
vendored
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
package rfc3962
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/jcmturner/gofork/x/crypto/pbkdf2"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/crypto/etype"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
s2kParamsZero = 4294967296
|
||||||
|
)
|
||||||
|
|
||||||
|
// StringToKey returns a key derived from the string provided according to the definition in RFC 3961.
|
||||||
|
func StringToKey(secret, salt, s2kparams string, e etype.EType) ([]byte, error) {
|
||||||
|
i, err := S2KparamsToItertions(s2kparams)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return StringToKeyIter(secret, salt, i, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringToPBKDF2 generates an encryption key from a pass phrase and salt string using the PBKDF2 function from PKCS #5 v2.0
|
||||||
|
func StringToPBKDF2(secret, salt string, iterations int64, e etype.EType) []byte {
|
||||||
|
return pbkdf2.Key64([]byte(secret), []byte(salt), iterations, int64(e.GetKeyByteSize()), e.GetHashFunc())
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringToKeyIter returns a key derived from the string provided according to the definition in RFC 3961.
|
||||||
|
func StringToKeyIter(secret, salt string, iterations int64, e etype.EType) ([]byte, error) {
|
||||||
|
tkey := e.RandomToKey(StringToPBKDF2(secret, salt, iterations, e))
|
||||||
|
return e.DeriveKey(tkey, []byte("kerberos"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// S2KparamsToItertions converts the string representation of iterations to an integer
|
||||||
|
func S2KparamsToItertions(s2kparams string) (int64, error) {
|
||||||
|
//The s2kparams string should be hex string representing 4 bytes
|
||||||
|
//The 4 bytes represent a number in big endian order
|
||||||
|
//If the value is zero then the number of iterations should be 4,294,967,296 (2^32)
|
||||||
|
var i uint32
|
||||||
|
if len(s2kparams) != 8 {
|
||||||
|
return int64(s2kParamsZero), errors.New("invalid s2kparams length")
|
||||||
|
}
|
||||||
|
b, err := hex.DecodeString(s2kparams)
|
||||||
|
if err != nil {
|
||||||
|
return int64(s2kParamsZero), errors.New("invalid s2kparams, cannot decode string to bytes")
|
||||||
|
}
|
||||||
|
i = binary.BigEndian.Uint32(b)
|
||||||
|
return int64(i), nil
|
||||||
|
}
|
40
vendor/github.com/jcmturner/gokrb5/v8/crypto/rfc4757/checksum.go
generated
vendored
Normal file
40
vendor/github.com/jcmturner/gokrb5/v8/crypto/rfc4757/checksum.go
generated
vendored
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
package rfc4757
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/hmac"
|
||||||
|
"crypto/md5"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Checksum returns a hash of the data in accordance with RFC 4757
|
||||||
|
func Checksum(key []byte, usage uint32, data []byte) ([]byte, error) {
|
||||||
|
// Create hashing key
|
||||||
|
s := append([]byte(`signaturekey`), byte(0x00)) //includes zero octet at end
|
||||||
|
mac := hmac.New(md5.New, key)
|
||||||
|
mac.Write(s)
|
||||||
|
Ksign := mac.Sum(nil)
|
||||||
|
|
||||||
|
// Format data
|
||||||
|
tb := UsageToMSMsgType(usage)
|
||||||
|
p := append(tb, data...)
|
||||||
|
h := md5.New()
|
||||||
|
rb := bytes.NewReader(p)
|
||||||
|
_, err := io.Copy(h, rb)
|
||||||
|
if err != nil {
|
||||||
|
return []byte{}, err
|
||||||
|
}
|
||||||
|
tmp := h.Sum(nil)
|
||||||
|
|
||||||
|
// Generate HMAC
|
||||||
|
mac = hmac.New(md5.New, Ksign)
|
||||||
|
mac.Write(tmp)
|
||||||
|
return mac.Sum(nil), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// HMAC returns a keyed MD5 checksum of the data
|
||||||
|
func HMAC(key []byte, data []byte) []byte {
|
||||||
|
mac := hmac.New(md5.New, key)
|
||||||
|
mac.Write(data)
|
||||||
|
return mac.Sum(nil)
|
||||||
|
}
|
80
vendor/github.com/jcmturner/gokrb5/v8/crypto/rfc4757/encryption.go
generated
vendored
Normal file
80
vendor/github.com/jcmturner/gokrb5/v8/crypto/rfc4757/encryption.go
generated
vendored
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
// Package rfc4757 provides encryption and checksum methods as specified in RFC 4757
|
||||||
|
package rfc4757
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/hmac"
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/rc4"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/jcmturner/gokrb5/v8/crypto/etype"
|
||||||
|
)
|
||||||
|
|
||||||
|
// EncryptData encrypts the data provided using methods specific to the etype provided as defined in RFC 4757.
|
||||||
|
func EncryptData(key, data []byte, e etype.EType) ([]byte, error) {
|
||||||
|
if len(key) != e.GetKeyByteSize() {
|
||||||
|
return []byte{}, fmt.Errorf("incorrect keysize: expected: %v actual: %v", e.GetKeyByteSize(), len(key))
|
||||||
|
}
|
||||||
|
rc4Cipher, err := rc4.NewCipher(key)
|
||||||
|
if err != nil {
|
||||||
|
return []byte{}, fmt.Errorf("error creating RC4 cipher: %v", err)
|
||||||
|
}
|
||||||
|
ed := make([]byte, len(data))
|
||||||
|
copy(ed, data)
|
||||||
|
rc4Cipher.XORKeyStream(ed, ed)
|
||||||
|
rc4Cipher.Reset()
|
||||||
|
return ed, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecryptData decrypts the data provided using the methods specific to the etype provided as defined in RFC 4757.
|
||||||
|
func DecryptData(key, data []byte, e etype.EType) ([]byte, error) {
|
||||||
|
return EncryptData(key, data, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncryptMessage encrypts the message provided using the methods specific to the etype provided as defined in RFC 4757.
|
||||||
|
// The encrypted data is concatenated with its RC4 header containing integrity checksum and confounder to create an encrypted message.
|
||||||
|
func EncryptMessage(key, data []byte, usage uint32, export bool, e etype.EType) ([]byte, error) {
|
||||||
|
confounder := make([]byte, e.GetConfounderByteSize()) // size = 8
|
||||||
|
_, err := rand.Read(confounder)
|
||||||
|
if err != nil {
|
||||||
|
return []byte{}, fmt.Errorf("error generating confounder: %v", err)
|
||||||
|
}
|
||||||
|
k1 := key
|
||||||
|
k2 := HMAC(k1, UsageToMSMsgType(usage))
|
||||||
|
toenc := append(confounder, data...)
|
||||||
|
chksum := HMAC(k2, toenc)
|
||||||
|
k3 := HMAC(k2, chksum)
|
||||||
|
|
||||||
|
ed, err := EncryptData(k3, toenc, e)
|
||||||
|
if err != nil {
|
||||||
|
return []byte{}, fmt.Errorf("error encrypting data: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
msg := append(chksum, ed...)
|
||||||
|
return msg, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecryptMessage decrypts the message provided using the methods specific to the etype provided as defined in RFC 4757.
|
||||||
|
// The integrity of the message is also verified.
|
||||||
|
func DecryptMessage(key, data []byte, usage uint32, export bool, e etype.EType) ([]byte, error) {
|
||||||
|
checksum := data[:e.GetHMACBitLength()/8]
|
||||||
|
ct := data[e.GetHMACBitLength()/8:]
|
||||||
|
_, k2, k3 := deriveKeys(key, checksum, usage, export)
|
||||||
|
|
||||||
|
pt, err := DecryptData(k3, ct, e)
|
||||||
|
if err != nil {
|
||||||
|
return []byte{}, fmt.Errorf("error decrypting data: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !VerifyIntegrity(k2, pt, data, e) {
|
||||||
|
return []byte{}, errors.New("integrity checksum incorrect")
|
||||||
|
}
|
||||||
|
return pt[e.GetConfounderByteSize():], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyIntegrity checks the integrity checksum of the data matches that calculated from the decrypted data.
|
||||||
|
func VerifyIntegrity(key, pt, data []byte, e etype.EType) bool {
|
||||||
|
chksum := HMAC(key, pt)
|
||||||
|
return hmac.Equal(chksum, data[:e.GetHMACBitLength()/8])
|
||||||
|
}
|
40
vendor/github.com/jcmturner/gokrb5/v8/crypto/rfc4757/keyDerivation.go
generated
vendored
Normal file
40
vendor/github.com/jcmturner/gokrb5/v8/crypto/rfc4757/keyDerivation.go
generated
vendored
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
package rfc4757
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/md4"
|
||||||
|
)
|
||||||
|
|
||||||
|
// StringToKey returns a key derived from the string provided according to the definition in RFC 4757.
|
||||||
|
func StringToKey(secret string) ([]byte, error) {
|
||||||
|
b := make([]byte, len(secret)*2, len(secret)*2)
|
||||||
|
for i, r := range secret {
|
||||||
|
u := fmt.Sprintf("%04x", r)
|
||||||
|
c, err := hex.DecodeString(u)
|
||||||
|
if err != nil {
|
||||||
|
return []byte{}, errors.New("character could not be encoded")
|
||||||
|
}
|
||||||
|
// Swap round the two bytes to make little endian as we put into byte slice
|
||||||
|
b[2*i] = c[1]
|
||||||
|
b[2*i+1] = c[0]
|
||||||
|
}
|
||||||
|
r := bytes.NewReader(b)
|
||||||
|
h := md4.New()
|
||||||
|
_, err := io.Copy(h, r)
|
||||||
|
if err != nil {
|
||||||
|
return []byte{}, err
|
||||||
|
}
|
||||||
|
return h.Sum(nil), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func deriveKeys(key, checksum []byte, usage uint32, export bool) (k1, k2, k3 []byte) {
|
||||||
|
k1 = key
|
||||||
|
k2 = HMAC(k1, UsageToMSMsgType(usage))
|
||||||
|
k3 = HMAC(k2, checksum)
|
||||||
|
return
|
||||||
|
}
|
20
vendor/github.com/jcmturner/gokrb5/v8/crypto/rfc4757/msgtype.go
generated
vendored
Normal file
20
vendor/github.com/jcmturner/gokrb5/v8/crypto/rfc4757/msgtype.go
generated
vendored
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
package rfc4757
|
||||||
|
|
||||||
|
import "encoding/binary"
|
||||||
|
|
||||||
|
// UsageToMSMsgType converts Kerberos key usage numbers to Microsoft message type encoded as a little-endian four byte slice.
|
||||||
|
func UsageToMSMsgType(usage uint32) []byte {
|
||||||
|
// Translate usage numbers to the Microsoft T numbers
|
||||||
|
switch usage {
|
||||||
|
case 3:
|
||||||
|
usage = 8
|
||||||
|
case 9:
|
||||||
|
usage = 8
|
||||||
|
case 23:
|
||||||
|
usage = 13
|
||||||
|
}
|
||||||
|
// Now convert to bytes
|
||||||
|
tb := make([]byte, 4) // We force an int32 input so we can't go over 4 bytes
|
||||||
|
binary.PutUvarint(tb, uint64(usage))
|
||||||
|
return tb
|
||||||
|
}
|
125
vendor/github.com/jcmturner/gokrb5/v8/crypto/rfc8009/encryption.go
generated
vendored
Normal file
125
vendor/github.com/jcmturner/gokrb5/v8/crypto/rfc8009/encryption.go
generated
vendored
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
// Package rfc8009 provides encryption and checksum methods as specified in RFC 8009
|
||||||
|
package rfc8009
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/aes"
|
||||||
|
"crypto/hmac"
|
||||||
|
"crypto/rand"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/jcmturner/aescts/v2"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/crypto/common"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/crypto/etype"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/etypeID"
|
||||||
|
)
|
||||||
|
|
||||||
|
// EncryptData encrypts the data provided using methods specific to the etype provided as defined in RFC 8009.
|
||||||
|
func EncryptData(key, data []byte, e etype.EType) ([]byte, []byte, error) {
|
||||||
|
kl := e.GetKeyByteSize()
|
||||||
|
if e.GetETypeID() == etypeID.AES256_CTS_HMAC_SHA384_192 {
|
||||||
|
kl = 32
|
||||||
|
}
|
||||||
|
if len(key) != kl {
|
||||||
|
return []byte{}, []byte{}, fmt.Errorf("incorrect keysize: expected: %v actual: %v", e.GetKeyByteSize(), len(key))
|
||||||
|
}
|
||||||
|
ivz := make([]byte, aes.BlockSize)
|
||||||
|
return aescts.Encrypt(key, ivz, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncryptMessage encrypts the message provided using the methods specific to the etype provided as defined in RFC 8009.
|
||||||
|
// The encrypted data is concatenated with its integrity hash to create an encrypted message.
|
||||||
|
func EncryptMessage(key, message []byte, usage uint32, e etype.EType) ([]byte, []byte, error) {
|
||||||
|
kl := e.GetKeyByteSize()
|
||||||
|
if e.GetETypeID() == etypeID.AES256_CTS_HMAC_SHA384_192 {
|
||||||
|
kl = 32
|
||||||
|
}
|
||||||
|
if len(key) != kl {
|
||||||
|
return []byte{}, []byte{}, fmt.Errorf("incorrect keysize: expected: %v actual: %v", kl, len(key))
|
||||||
|
}
|
||||||
|
if len(key) != e.GetKeyByteSize() {
|
||||||
|
}
|
||||||
|
//confounder
|
||||||
|
c := make([]byte, e.GetConfounderByteSize())
|
||||||
|
_, err := rand.Read(c)
|
||||||
|
if err != nil {
|
||||||
|
return []byte{}, []byte{}, fmt.Errorf("could not generate random confounder: %v", err)
|
||||||
|
}
|
||||||
|
plainBytes := append(c, message...)
|
||||||
|
|
||||||
|
// Derive key for encryption from usage
|
||||||
|
var k []byte
|
||||||
|
if usage != 0 {
|
||||||
|
k, err = e.DeriveKey(key, common.GetUsageKe(usage))
|
||||||
|
if err != nil {
|
||||||
|
return []byte{}, []byte{}, fmt.Errorf("error deriving key for encryption: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encrypt the data
|
||||||
|
iv, b, err := e.EncryptData(k, plainBytes)
|
||||||
|
if err != nil {
|
||||||
|
return iv, b, fmt.Errorf("error encrypting data: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ivz := make([]byte, e.GetConfounderByteSize())
|
||||||
|
ih, err := GetIntegityHash(ivz, b, key, usage, e)
|
||||||
|
if err != nil {
|
||||||
|
return iv, b, fmt.Errorf("error encrypting data: %v", err)
|
||||||
|
}
|
||||||
|
b = append(b, ih...)
|
||||||
|
return iv, b, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecryptData decrypts the data provided using the methods specific to the etype provided as defined in RFC 8009.
|
||||||
|
func DecryptData(key, data []byte, e etype.EType) ([]byte, error) {
|
||||||
|
kl := e.GetKeyByteSize()
|
||||||
|
if e.GetETypeID() == etypeID.AES256_CTS_HMAC_SHA384_192 {
|
||||||
|
kl = 32
|
||||||
|
}
|
||||||
|
if len(key) != kl {
|
||||||
|
return []byte{}, fmt.Errorf("incorrect keysize: expected: %v actual: %v", kl, len(key))
|
||||||
|
}
|
||||||
|
ivz := make([]byte, aes.BlockSize)
|
||||||
|
return aescts.Decrypt(key, ivz, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecryptMessage decrypts the message provided using the methods specific to the etype provided as defined in RFC 8009.
|
||||||
|
// The integrity of the message is also verified.
|
||||||
|
func DecryptMessage(key, ciphertext []byte, usage uint32, e etype.EType) ([]byte, error) {
|
||||||
|
//Derive the key
|
||||||
|
k, err := e.DeriveKey(key, common.GetUsageKe(usage))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error deriving key: %v", err)
|
||||||
|
}
|
||||||
|
// Strip off the checksum from the end
|
||||||
|
b, err := e.DecryptData(k, ciphertext[:len(ciphertext)-e.GetHMACBitLength()/8])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
//Verify checksum
|
||||||
|
if !e.VerifyIntegrity(key, ciphertext, b, usage) {
|
||||||
|
return nil, errors.New("integrity verification failed")
|
||||||
|
}
|
||||||
|
//Remove the confounder bytes
|
||||||
|
return b[e.GetConfounderByteSize():], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetIntegityHash returns a keyed integrity hash of the bytes provided as defined in RFC 8009
|
||||||
|
func GetIntegityHash(iv, c, key []byte, usage uint32, e etype.EType) ([]byte, error) {
|
||||||
|
// Generate and append integrity hash
|
||||||
|
// Rather than calculating the hash over the confounder and plaintext
|
||||||
|
// it is calculated over the iv concatenated with the AES cipher output.
|
||||||
|
ib := append(iv, c...)
|
||||||
|
return common.GetIntegrityHash(ib, key, usage, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyIntegrity verifies the integrity of cipertext bytes ct.
|
||||||
|
func VerifyIntegrity(key, ct []byte, usage uint32, etype etype.EType) bool {
|
||||||
|
h := make([]byte, etype.GetHMACBitLength()/8)
|
||||||
|
copy(h, ct[len(ct)-etype.GetHMACBitLength()/8:])
|
||||||
|
ivz := make([]byte, etype.GetConfounderByteSize())
|
||||||
|
ib := append(ivz, ct[:len(ct)-(etype.GetHMACBitLength()/8)]...)
|
||||||
|
expectedMAC, _ := common.GetIntegrityHash(ib, key, usage, etype)
|
||||||
|
return hmac.Equal(h, expectedMAC)
|
||||||
|
}
|
135
vendor/github.com/jcmturner/gokrb5/v8/crypto/rfc8009/keyDerivation.go
generated
vendored
Normal file
135
vendor/github.com/jcmturner/gokrb5/v8/crypto/rfc8009/keyDerivation.go
generated
vendored
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
package rfc8009
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/hmac"
|
||||||
|
"encoding/binary"
|
||||||
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/jcmturner/gokrb5/v8/crypto/etype"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/etypeID"
|
||||||
|
"golang.org/x/crypto/pbkdf2"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
s2kParamsZero = 32768
|
||||||
|
)
|
||||||
|
|
||||||
|
// DeriveRandom for key derivation as defined in RFC 8009
|
||||||
|
func DeriveRandom(protocolKey, usage []byte, e etype.EType) ([]byte, error) {
|
||||||
|
h := e.GetHashFunc()()
|
||||||
|
return KDF_HMAC_SHA2(protocolKey, []byte("prf"), usage, h.Size(), e), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeriveKey derives a key from the protocol key based on the usage and the etype's specific methods.
|
||||||
|
//
|
||||||
|
// https://tools.ietf.org/html/rfc8009#section-5
|
||||||
|
func DeriveKey(protocolKey, label []byte, e etype.EType) []byte {
|
||||||
|
var context []byte
|
||||||
|
var kl int
|
||||||
|
// Key length is longer for aes256-cts-hmac-sha384-192 is it is a Ke or from StringToKey (where label is "kerberos")
|
||||||
|
if e.GetETypeID() == etypeID.AES256_CTS_HMAC_SHA384_192 {
|
||||||
|
Swtch:
|
||||||
|
switch label[len(label)-1] {
|
||||||
|
case 0x73:
|
||||||
|
// 0x73 is "s" so label could be kerberos meaning StringToKey so now check if the label is "kerberos"
|
||||||
|
kerblabel := []byte("kerberos")
|
||||||
|
if len(label) != len(kerblabel) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
for i, b := range label {
|
||||||
|
if b != kerblabel[i] {
|
||||||
|
kl = e.GetKeySeedBitLength()
|
||||||
|
break Swtch
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if kl == 0 {
|
||||||
|
// This is StringToKey
|
||||||
|
kl = 256
|
||||||
|
}
|
||||||
|
case 0xAA:
|
||||||
|
// This is a Ke
|
||||||
|
kl = 256
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if kl == 0 {
|
||||||
|
kl = e.GetKeySeedBitLength()
|
||||||
|
}
|
||||||
|
return e.RandomToKey(KDF_HMAC_SHA2(protocolKey, label, context, kl, e))
|
||||||
|
}
|
||||||
|
|
||||||
|
// RandomToKey returns a key from the bytes provided according to the definition in RFC 8009.
|
||||||
|
func RandomToKey(b []byte) []byte {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringToKey returns a key derived from the string provided according to the definition in RFC 8009.
|
||||||
|
func StringToKey(secret, salt, s2kparams string, e etype.EType) ([]byte, error) {
|
||||||
|
i, err := S2KparamsToItertions(s2kparams)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return StringToKeyIter(secret, salt, i, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringToKeyIter returns a key derived from the string provided according to the definition in RFC 8009.
|
||||||
|
func StringToKeyIter(secret, salt string, iterations int, e etype.EType) ([]byte, error) {
|
||||||
|
tkey := e.RandomToKey(StringToPBKDF2(secret, salt, iterations, e))
|
||||||
|
return e.DeriveKey(tkey, []byte("kerberos"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringToPBKDF2 generates an encryption key from a pass phrase and salt string using the PBKDF2 function from PKCS #5 v2.0
|
||||||
|
func StringToPBKDF2(secret, salt string, iterations int, e etype.EType) []byte {
|
||||||
|
kl := e.GetKeyByteSize()
|
||||||
|
if e.GetETypeID() == etypeID.AES256_CTS_HMAC_SHA384_192 {
|
||||||
|
kl = 32
|
||||||
|
}
|
||||||
|
return pbkdf2.Key([]byte(secret), []byte(salt), iterations, kl, e.GetHashFunc())
|
||||||
|
}
|
||||||
|
|
||||||
|
// KDF_HMAC_SHA2 key derivation: https://tools.ietf.org/html/rfc8009#section-3
|
||||||
|
func KDF_HMAC_SHA2(protocolKey, label, context []byte, kl int, e etype.EType) []byte {
|
||||||
|
//k: Length in bits of the key to be outputted, expressed in big-endian binary representation in 4 bytes.
|
||||||
|
k := make([]byte, 4, 4)
|
||||||
|
binary.BigEndian.PutUint32(k, uint32(kl))
|
||||||
|
|
||||||
|
c := make([]byte, 4, 4)
|
||||||
|
binary.BigEndian.PutUint32(c, uint32(1))
|
||||||
|
c = append(c, label...)
|
||||||
|
c = append(c, byte(0))
|
||||||
|
if len(context) > 0 {
|
||||||
|
c = append(c, context...)
|
||||||
|
}
|
||||||
|
c = append(c, k...)
|
||||||
|
|
||||||
|
mac := hmac.New(e.GetHashFunc(), protocolKey)
|
||||||
|
mac.Write(c)
|
||||||
|
return mac.Sum(nil)[:(kl / 8)]
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSaltP returns the salt value based on the etype name: https://tools.ietf.org/html/rfc8009#section-4
|
||||||
|
func GetSaltP(salt, ename string) string {
|
||||||
|
b := []byte(ename)
|
||||||
|
b = append(b, byte(0))
|
||||||
|
b = append(b, []byte(salt)...)
|
||||||
|
return string(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// S2KparamsToItertions converts the string representation of iterations to an integer for RFC 8009.
|
||||||
|
func S2KparamsToItertions(s2kparams string) (int, error) {
|
||||||
|
var i uint32
|
||||||
|
if len(s2kparams) != 8 {
|
||||||
|
return s2kParamsZero, errors.New("Invalid s2kparams length")
|
||||||
|
}
|
||||||
|
b, err := hex.DecodeString(s2kparams)
|
||||||
|
if err != nil {
|
||||||
|
return s2kParamsZero, errors.New("Invalid s2kparams, cannot decode string to bytes")
|
||||||
|
}
|
||||||
|
i = binary.BigEndian.Uint32(b)
|
||||||
|
//buf := bytes.NewBuffer(b)
|
||||||
|
//err = binary.Read(buf, binary.BigEndian, &i)
|
||||||
|
if err != nil {
|
||||||
|
return s2kParamsZero, errors.New("Invalid s2kparams, cannot convert to big endian int32")
|
||||||
|
}
|
||||||
|
return int(i), nil
|
||||||
|
}
|
174
vendor/github.com/jcmturner/gokrb5/v8/gssapi/MICToken.go
generated
vendored
Normal file
174
vendor/github.com/jcmturner/gokrb5/v8/gssapi/MICToken.go
generated
vendored
Normal file
|
@ -0,0 +1,174 @@
|
||||||
|
package gssapi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/hmac"
|
||||||
|
"encoding/binary"
|
||||||
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/jcmturner/gokrb5/v8/crypto"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/keyusage"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RFC 4121, section 4.2.6.1
|
||||||
|
|
||||||
|
const (
|
||||||
|
// MICTokenFlagSentByAcceptor - this flag indicates the sender is the context acceptor. When not set, it indicates the sender is the context initiator
|
||||||
|
MICTokenFlagSentByAcceptor = 1 << iota
|
||||||
|
// MICTokenFlagSealed - this flag indicates confidentiality is provided for. It SHALL NOT be set in MIC tokens
|
||||||
|
MICTokenFlagSealed
|
||||||
|
// MICTokenFlagAcceptorSubkey - a subkey asserted by the context acceptor is used to protect the message
|
||||||
|
MICTokenFlagAcceptorSubkey
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
micHdrLen = 16 // Length of the MIC Token's header
|
||||||
|
)
|
||||||
|
|
||||||
|
// MICToken represents a GSS API MIC token, as defined in RFC 4121.
|
||||||
|
// It contains the header fields, the payload (this is not transmitted) and
|
||||||
|
// the checksum, and provides the logic for converting to/from bytes plus
|
||||||
|
// computing and verifying checksums
|
||||||
|
type MICToken struct {
|
||||||
|
// const GSS Token ID: 0x0404
|
||||||
|
Flags byte // contains three flags: acceptor, sealed, acceptor subkey
|
||||||
|
// const Filler: 0xFF 0xFF 0xFF 0xFF 0xFF
|
||||||
|
SndSeqNum uint64 // sender's sequence number. big-endian
|
||||||
|
Payload []byte // your data! :)
|
||||||
|
Checksum []byte // checksum of { payload | header }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the 2 bytes identifying a GSS API MIC token
|
||||||
|
func getGSSMICTokenID() *[2]byte {
|
||||||
|
return &[2]byte{0x04, 0x04}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the filler bytes used in header
|
||||||
|
func fillerBytes() *[5]byte {
|
||||||
|
return &[5]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marshal the MICToken into a byte slice.
|
||||||
|
// The payload should have been set and the checksum computed, otherwise an error is returned.
|
||||||
|
func (mt *MICToken) Marshal() ([]byte, error) {
|
||||||
|
if mt.Checksum == nil {
|
||||||
|
return nil, errors.New("checksum has not been set")
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes := make([]byte, micHdrLen+len(mt.Checksum))
|
||||||
|
copy(bytes[0:micHdrLen], mt.getMICChecksumHeader()[:])
|
||||||
|
copy(bytes[micHdrLen:], mt.Checksum)
|
||||||
|
|
||||||
|
return bytes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetChecksum uses the passed encryption key and key usage to compute the checksum over the payload and
|
||||||
|
// the header, and sets the Checksum field of this MICToken.
|
||||||
|
// If the payload has not been set or the checksum has already been set, an error is returned.
|
||||||
|
func (mt *MICToken) SetChecksum(key types.EncryptionKey, keyUsage uint32) error {
|
||||||
|
if mt.Checksum != nil {
|
||||||
|
return errors.New("checksum has already been computed")
|
||||||
|
}
|
||||||
|
checksum, err := mt.checksum(key, keyUsage)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
mt.Checksum = checksum
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute and return the checksum of this token, computed using the passed key and key usage.
|
||||||
|
// Note: This will NOT update the struct's Checksum field.
|
||||||
|
func (mt *MICToken) checksum(key types.EncryptionKey, keyUsage uint32) ([]byte, error) {
|
||||||
|
if mt.Payload == nil {
|
||||||
|
return nil, errors.New("cannot compute checksum with uninitialized payload")
|
||||||
|
}
|
||||||
|
d := make([]byte, micHdrLen+len(mt.Payload))
|
||||||
|
copy(d[0:], mt.Payload)
|
||||||
|
copy(d[len(mt.Payload):], mt.getMICChecksumHeader())
|
||||||
|
|
||||||
|
encType, err := crypto.GetEtype(key.KeyType)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return encType.GetChecksumHash(key.KeyValue, d, keyUsage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build a header suitable for a checksum computation
|
||||||
|
func (mt *MICToken) getMICChecksumHeader() []byte {
|
||||||
|
header := make([]byte, micHdrLen)
|
||||||
|
copy(header[0:2], getGSSMICTokenID()[:])
|
||||||
|
header[2] = mt.Flags
|
||||||
|
copy(header[3:8], fillerBytes()[:])
|
||||||
|
binary.BigEndian.PutUint64(header[8:16], mt.SndSeqNum)
|
||||||
|
return header
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify computes the token's checksum with the provided key and usage,
|
||||||
|
// and compares it to the checksum present in the token.
|
||||||
|
// In case of any failure, (false, err) is returned, with err an explanatory error.
|
||||||
|
func (mt *MICToken) Verify(key types.EncryptionKey, keyUsage uint32) (bool, error) {
|
||||||
|
computed, err := mt.checksum(key, keyUsage)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if !hmac.Equal(computed, mt.Checksum) {
|
||||||
|
return false, fmt.Errorf(
|
||||||
|
"checksum mismatch. Computed: %s, Contained in token: %s",
|
||||||
|
hex.EncodeToString(computed), hex.EncodeToString(mt.Checksum))
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshal bytes into the corresponding MICToken.
|
||||||
|
// If expectFromAcceptor is true we expect the token to have been emitted by the gss acceptor,
|
||||||
|
// and will check the according flag, returning an error if the token does not match the expectation.
|
||||||
|
func (mt *MICToken) Unmarshal(b []byte, expectFromAcceptor bool) error {
|
||||||
|
if len(b) < micHdrLen {
|
||||||
|
return errors.New("bytes shorter than header length")
|
||||||
|
}
|
||||||
|
if !bytes.Equal(getGSSMICTokenID()[:], b[0:2]) {
|
||||||
|
return fmt.Errorf("wrong Token ID, Expected %s, was %s",
|
||||||
|
hex.EncodeToString(getGSSMICTokenID()[:]),
|
||||||
|
hex.EncodeToString(b[0:2]))
|
||||||
|
}
|
||||||
|
flags := b[2]
|
||||||
|
isFromAcceptor := flags&MICTokenFlagSentByAcceptor != 0
|
||||||
|
if isFromAcceptor && !expectFromAcceptor {
|
||||||
|
return errors.New("unexpected acceptor flag is set: not expecting a token from the acceptor")
|
||||||
|
}
|
||||||
|
if !isFromAcceptor && expectFromAcceptor {
|
||||||
|
return errors.New("unexpected acceptor flag is not set: expecting a token from the acceptor, not in the initiator")
|
||||||
|
}
|
||||||
|
if !bytes.Equal(b[3:8], fillerBytes()[:]) {
|
||||||
|
return fmt.Errorf("unexpected filler bytes: expecting %s, was %s",
|
||||||
|
hex.EncodeToString(fillerBytes()[:]),
|
||||||
|
hex.EncodeToString(b[3:8]))
|
||||||
|
}
|
||||||
|
|
||||||
|
mt.Flags = flags
|
||||||
|
mt.SndSeqNum = binary.BigEndian.Uint64(b[8:16])
|
||||||
|
mt.Checksum = b[micHdrLen:]
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewInitiatorMICToken builds a new initiator token (acceptor flag will be set to 0) and computes the authenticated checksum.
|
||||||
|
// Other flags are set to 0.
|
||||||
|
// Note that in certain circumstances you may need to provide a sequence number that has been defined earlier.
|
||||||
|
// This is currently not supported.
|
||||||
|
func NewInitiatorMICToken(payload []byte, key types.EncryptionKey) (*MICToken, error) {
|
||||||
|
token := MICToken{
|
||||||
|
Flags: 0x00,
|
||||||
|
SndSeqNum: 0,
|
||||||
|
Payload: payload,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := token.SetChecksum(key, keyusage.GSSAPI_INITIATOR_SIGN); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &token, nil
|
||||||
|
}
|
20
vendor/github.com/jcmturner/gokrb5/v8/gssapi/README.md
generated
vendored
Normal file
20
vendor/github.com/jcmturner/gokrb5/v8/gssapi/README.md
generated
vendored
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
# Notes on GSS-API Negotiation Mechanism
|
||||||
|
https://tools.ietf.org/html/rfc4178
|
||||||
|
|
||||||
|
Client sends an initial negotiation message to the server which specifies the list of mechanisms
|
||||||
|
the client can support in order of decreasing preference.
|
||||||
|
This message is generated with the ``NewNegTokenInitKrb5`` method.
|
||||||
|
The message generated by this function specifies only a kerberos v5 mechanism is supported.
|
||||||
|
|
||||||
|
The RFC states that this message can optionally contain the initial mechanism token
|
||||||
|
for the preferred mechanism (KRB5 in this case) of the client. The ``NewNegTokenInitKrb5``
|
||||||
|
includes this in the message.
|
||||||
|
|
||||||
|
The server side responds to this message with a one of four messages:
|
||||||
|
|
||||||
|
| Message Type/State | Description |
|
||||||
|
|--------------------|-------------|
|
||||||
|
| accept-completed | indicates that the initiator-selected mechanism was acceptable to the target, and that the security mechanism token embedded in the first negotiation message was sufficient to complete the authentication |
|
||||||
|
| accept-incomplete | At least one more message is needed from the client to establish security context. |
|
||||||
|
| reject | Negotiation is being terminated. |
|
||||||
|
| request-mic | (this state can only be present in the first reply message from the target) indicates that the MIC token exchange is REQUIRED if per-message integrity services are available |
|
25
vendor/github.com/jcmturner/gokrb5/v8/gssapi/contextFlags.go
generated
vendored
Normal file
25
vendor/github.com/jcmturner/gokrb5/v8/gssapi/contextFlags.go
generated
vendored
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
package gssapi
|
||||||
|
|
||||||
|
import "github.com/jcmturner/gofork/encoding/asn1"
|
||||||
|
|
||||||
|
// GSS-API context flags assigned numbers.
|
||||||
|
const (
|
||||||
|
ContextFlagDeleg = 1
|
||||||
|
ContextFlagMutual = 2
|
||||||
|
ContextFlagReplay = 4
|
||||||
|
ContextFlagSequence = 8
|
||||||
|
ContextFlagConf = 16
|
||||||
|
ContextFlagInteg = 32
|
||||||
|
ContextFlagAnon = 64
|
||||||
|
)
|
||||||
|
|
||||||
|
// ContextFlags flags for GSSAPI
|
||||||
|
type ContextFlags asn1.BitString
|
||||||
|
|
||||||
|
// NewContextFlags creates a new ContextFlags instance.
|
||||||
|
func NewContextFlags() ContextFlags {
|
||||||
|
var c ContextFlags
|
||||||
|
c.BitLength = 32
|
||||||
|
c.Bytes = make([]byte, 4)
|
||||||
|
return c
|
||||||
|
}
|
202
vendor/github.com/jcmturner/gokrb5/v8/gssapi/gssapi.go
generated
vendored
Normal file
202
vendor/github.com/jcmturner/gokrb5/v8/gssapi/gssapi.go
generated
vendored
Normal file
|
@ -0,0 +1,202 @@
|
||||||
|
// Package gssapi implements Generic Security Services Application Program Interface required for SPNEGO kerberos authentication.
|
||||||
|
package gssapi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/jcmturner/gofork/encoding/asn1"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GSS-API OID names
|
||||||
|
const (
|
||||||
|
// GSS-API OID names
|
||||||
|
OIDKRB5 OIDName = "KRB5" // MechType OID for Kerberos 5
|
||||||
|
OIDMSLegacyKRB5 OIDName = "MSLegacyKRB5" // MechType OID for Kerberos 5
|
||||||
|
OIDSPNEGO OIDName = "SPNEGO"
|
||||||
|
OIDGSSIAKerb OIDName = "GSSIAKerb" // Indicates the client cannot get a service ticket and asks the server to serve as an intermediate to the target KDC. http://k5wiki.kerberos.org/wiki/Projects/IAKERB#IAKERB_mech
|
||||||
|
)
|
||||||
|
|
||||||
|
// GSS-API status values
|
||||||
|
const (
|
||||||
|
StatusBadBindings = 1 << iota
|
||||||
|
StatusBadMech
|
||||||
|
StatusBadName
|
||||||
|
StatusBadNameType
|
||||||
|
StatusBadStatus
|
||||||
|
StatusBadSig
|
||||||
|
StatusBadMIC
|
||||||
|
StatusContextExpired
|
||||||
|
StatusCredentialsExpired
|
||||||
|
StatusDefectiveCredential
|
||||||
|
StatusDefectiveToken
|
||||||
|
StatusFailure
|
||||||
|
StatusNoContext
|
||||||
|
StatusNoCred
|
||||||
|
StatusBadQOP
|
||||||
|
StatusUnauthorized
|
||||||
|
StatusUnavailable
|
||||||
|
StatusDuplicateElement
|
||||||
|
StatusNameNotMN
|
||||||
|
StatusComplete
|
||||||
|
StatusContinueNeeded
|
||||||
|
StatusDuplicateToken
|
||||||
|
StatusOldToken
|
||||||
|
StatusUnseqToken
|
||||||
|
StatusGapToken
|
||||||
|
)
|
||||||
|
|
||||||
|
// ContextToken is an interface for a GSS-API context token.
|
||||||
|
type ContextToken interface {
|
||||||
|
Marshal() ([]byte, error)
|
||||||
|
Unmarshal(b []byte) error
|
||||||
|
Verify() (bool, Status)
|
||||||
|
Context() context.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
CREDENTIAL MANAGEMENT
|
||||||
|
|
||||||
|
GSS_Acquire_cred acquire credentials for use
|
||||||
|
GSS_Release_cred release credentials after use
|
||||||
|
GSS_Inquire_cred display information about credentials
|
||||||
|
GSS_Add_cred construct credentials incrementally
|
||||||
|
GSS_Inquire_cred_by_mech display per-mechanism credential information
|
||||||
|
|
||||||
|
CONTEXT-LEVEL CALLS
|
||||||
|
|
||||||
|
GSS_Init_sec_context initiate outbound security context
|
||||||
|
GSS_Accept_sec_context accept inbound security context
|
||||||
|
GSS_Delete_sec_context flush context when no longer needed
|
||||||
|
GSS_Process_context_token process received control token on context
|
||||||
|
GSS_Context_time indicate validity time remaining on context
|
||||||
|
GSS_Inquire_context display information about context
|
||||||
|
GSS_Wrap_size_limit determine GSS_Wrap token size limit
|
||||||
|
GSS_Export_sec_context transfer context to other process
|
||||||
|
GSS_Import_sec_context import transferred context
|
||||||
|
|
||||||
|
PER-MESSAGE CALLS
|
||||||
|
|
||||||
|
GSS_GetMIC apply integrity check, receive as token separate from message
|
||||||
|
GSS_VerifyMIC validate integrity check token along with message
|
||||||
|
GSS_Wrap sign, optionally encrypt, encapsulate
|
||||||
|
GSS_Unwrap decapsulate, decrypt if needed, validate integrity check
|
||||||
|
|
||||||
|
SUPPORT CALLS
|
||||||
|
|
||||||
|
GSS_Display_status translate status codes to printable form
|
||||||
|
GSS_Indicate_mechs indicate mech_types supported on local system
|
||||||
|
GSS_Compare_name compare two names for equality
|
||||||
|
GSS_Display_name translate name to printable form
|
||||||
|
GSS_Import_name convert printable name to normalized form
|
||||||
|
GSS_Release_name free storage of normalized-form name
|
||||||
|
GSS_Release_buffer free storage of general GSS-allocated object
|
||||||
|
GSS_Release_OID_set free storage of OID set object
|
||||||
|
GSS_Create_empty_OID_set create empty OID set
|
||||||
|
GSS_Add_OID_set_member add member to OID set
|
||||||
|
GSS_Test_OID_set_member test if OID is member of OID set
|
||||||
|
GSS_Inquire_names_for_mech indicate name types supported by mechanism
|
||||||
|
GSS_Inquire_mechs_for_name indicates mechanisms supporting name type
|
||||||
|
GSS_Canonicalize_name translate name to per-mechanism form
|
||||||
|
GSS_Export_name externalize per-mechanism name
|
||||||
|
GSS_Duplicate_name duplicate name object
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Mechanism is the GSS-API interface for authentication mechanisms.
|
||||||
|
type Mechanism interface {
|
||||||
|
OID() asn1.ObjectIdentifier
|
||||||
|
AcquireCred() error // acquire credentials for use (eg. AS exchange for KRB5)
|
||||||
|
InitSecContext() (ContextToken, error) // initiate outbound security context (eg TGS exchange builds AP_REQ to go into ContextToken to send to service)
|
||||||
|
AcceptSecContext(ct ContextToken) (bool, context.Context, Status) // service verifies the token server side to establish a context
|
||||||
|
MIC() MICToken // apply integrity check, receive as token separate from message
|
||||||
|
VerifyMIC(mt MICToken) (bool, error) // validate integrity check token along with message
|
||||||
|
Wrap(msg []byte) WrapToken // sign, optionally encrypt, encapsulate
|
||||||
|
Unwrap(wt WrapToken) []byte // decapsulate, decrypt if needed, validate integrity check
|
||||||
|
}
|
||||||
|
|
||||||
|
// OIDName is the type for defined GSS-API OIDs.
|
||||||
|
type OIDName string
|
||||||
|
|
||||||
|
// OID returns the OID for the provided OID name.
|
||||||
|
func (o OIDName) OID() asn1.ObjectIdentifier {
|
||||||
|
switch o {
|
||||||
|
case OIDSPNEGO:
|
||||||
|
return asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 2}
|
||||||
|
case OIDKRB5:
|
||||||
|
return asn1.ObjectIdentifier{1, 2, 840, 113554, 1, 2, 2}
|
||||||
|
case OIDMSLegacyKRB5:
|
||||||
|
return asn1.ObjectIdentifier{1, 2, 840, 48018, 1, 2, 2}
|
||||||
|
case OIDGSSIAKerb:
|
||||||
|
return asn1.ObjectIdentifier{1, 3, 6, 1, 5, 2, 5}
|
||||||
|
}
|
||||||
|
return asn1.ObjectIdentifier{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Status is the GSS-API status and implements the error interface.
|
||||||
|
type Status struct {
|
||||||
|
Code int
|
||||||
|
Message string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error returns the Status description.
|
||||||
|
func (s Status) Error() string {
|
||||||
|
var str string
|
||||||
|
switch s.Code {
|
||||||
|
case StatusBadBindings:
|
||||||
|
str = "channel binding mismatch"
|
||||||
|
case StatusBadMech:
|
||||||
|
str = "unsupported mechanism requested"
|
||||||
|
case StatusBadName:
|
||||||
|
str = "invalid name provided"
|
||||||
|
case StatusBadNameType:
|
||||||
|
str = "name of unsupported type provided"
|
||||||
|
case StatusBadStatus:
|
||||||
|
str = "invalid input status selector"
|
||||||
|
case StatusBadSig:
|
||||||
|
str = "token had invalid integrity check"
|
||||||
|
case StatusBadMIC:
|
||||||
|
str = "preferred alias for GSS_S_BAD_SIG"
|
||||||
|
case StatusContextExpired:
|
||||||
|
str = "specified security context expired"
|
||||||
|
case StatusCredentialsExpired:
|
||||||
|
str = "expired credentials detected"
|
||||||
|
case StatusDefectiveCredential:
|
||||||
|
str = "defective credential detected"
|
||||||
|
case StatusDefectiveToken:
|
||||||
|
str = "defective token detected"
|
||||||
|
case StatusFailure:
|
||||||
|
str = "failure, unspecified at GSS-API level"
|
||||||
|
case StatusNoContext:
|
||||||
|
str = "no valid security context specified"
|
||||||
|
case StatusNoCred:
|
||||||
|
str = "no valid credentials provided"
|
||||||
|
case StatusBadQOP:
|
||||||
|
str = "unsupported QOP valu"
|
||||||
|
case StatusUnauthorized:
|
||||||
|
str = "operation unauthorized"
|
||||||
|
case StatusUnavailable:
|
||||||
|
str = "operation unavailable"
|
||||||
|
case StatusDuplicateElement:
|
||||||
|
str = "duplicate credential element requested"
|
||||||
|
case StatusNameNotMN:
|
||||||
|
str = "name contains multi-mechanism elements"
|
||||||
|
case StatusComplete:
|
||||||
|
str = "normal completion"
|
||||||
|
case StatusContinueNeeded:
|
||||||
|
str = "continuation call to routine required"
|
||||||
|
case StatusDuplicateToken:
|
||||||
|
str = "duplicate per-message token detected"
|
||||||
|
case StatusOldToken:
|
||||||
|
str = "timed-out per-message token detected"
|
||||||
|
case StatusUnseqToken:
|
||||||
|
str = "reordered (early) per-message token detected"
|
||||||
|
case StatusGapToken:
|
||||||
|
str = "skipped predecessor token(s) detected"
|
||||||
|
default:
|
||||||
|
str = "unknown GSS-API error status"
|
||||||
|
}
|
||||||
|
if s.Message != "" {
|
||||||
|
return fmt.Sprintf("%s: %s", str, s.Message)
|
||||||
|
}
|
||||||
|
return str
|
||||||
|
}
|
193
vendor/github.com/jcmturner/gokrb5/v8/gssapi/wrapToken.go
generated
vendored
Normal file
193
vendor/github.com/jcmturner/gokrb5/v8/gssapi/wrapToken.go
generated
vendored
Normal file
|
@ -0,0 +1,193 @@
|
||||||
|
package gssapi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/hmac"
|
||||||
|
"encoding/binary"
|
||||||
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/jcmturner/gokrb5/v8/crypto"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/keyusage"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RFC 4121, section 4.2.6.2
|
||||||
|
|
||||||
|
const (
|
||||||
|
HdrLen = 16 // Length of the Wrap Token's header
|
||||||
|
FillerByte byte = 0xFF
|
||||||
|
)
|
||||||
|
|
||||||
|
// WrapToken represents a GSS API Wrap token, as defined in RFC 4121.
|
||||||
|
// It contains the header fields, the payload and the checksum, and provides
|
||||||
|
// the logic for converting to/from bytes plus computing and verifying checksums
|
||||||
|
type WrapToken struct {
|
||||||
|
// const GSS Token ID: 0x0504
|
||||||
|
Flags byte // contains three flags: acceptor, sealed, acceptor subkey
|
||||||
|
// const Filler: 0xFF
|
||||||
|
EC uint16 // checksum length. big-endian
|
||||||
|
RRC uint16 // right rotation count. big-endian
|
||||||
|
SndSeqNum uint64 // sender's sequence number. big-endian
|
||||||
|
Payload []byte // your data! :)
|
||||||
|
CheckSum []byte // authenticated checksum of { payload | header }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the 2 bytes identifying a GSS API Wrap token
|
||||||
|
func getGssWrapTokenId() *[2]byte {
|
||||||
|
return &[2]byte{0x05, 0x04}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marshal the WrapToken into a byte slice.
|
||||||
|
// The payload should have been set and the checksum computed, otherwise an error is returned.
|
||||||
|
func (wt *WrapToken) Marshal() ([]byte, error) {
|
||||||
|
if wt.CheckSum == nil {
|
||||||
|
return nil, errors.New("checksum has not been set")
|
||||||
|
}
|
||||||
|
if wt.Payload == nil {
|
||||||
|
return nil, errors.New("payload has not been set")
|
||||||
|
}
|
||||||
|
|
||||||
|
pldOffset := HdrLen // Offset of the payload in the token
|
||||||
|
chkSOffset := HdrLen + len(wt.Payload) // Offset of the checksum in the token
|
||||||
|
|
||||||
|
bytes := make([]byte, chkSOffset+int(wt.EC))
|
||||||
|
copy(bytes[0:], getGssWrapTokenId()[:])
|
||||||
|
bytes[2] = wt.Flags
|
||||||
|
bytes[3] = FillerByte
|
||||||
|
binary.BigEndian.PutUint16(bytes[4:6], wt.EC)
|
||||||
|
binary.BigEndian.PutUint16(bytes[6:8], wt.RRC)
|
||||||
|
binary.BigEndian.PutUint64(bytes[8:16], wt.SndSeqNum)
|
||||||
|
copy(bytes[pldOffset:], wt.Payload)
|
||||||
|
copy(bytes[chkSOffset:], wt.CheckSum)
|
||||||
|
return bytes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetCheckSum uses the passed encryption key and key usage to compute the checksum over the payload and
|
||||||
|
// the header, and sets the CheckSum field of this WrapToken.
|
||||||
|
// If the payload has not been set or the checksum has already been set, an error is returned.
|
||||||
|
func (wt *WrapToken) SetCheckSum(key types.EncryptionKey, keyUsage uint32) error {
|
||||||
|
if wt.Payload == nil {
|
||||||
|
return errors.New("payload has not been set")
|
||||||
|
}
|
||||||
|
if wt.CheckSum != nil {
|
||||||
|
return errors.New("checksum has already been computed")
|
||||||
|
}
|
||||||
|
chkSum, cErr := wt.computeCheckSum(key, keyUsage)
|
||||||
|
if cErr != nil {
|
||||||
|
return cErr
|
||||||
|
}
|
||||||
|
wt.CheckSum = chkSum
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ComputeCheckSum computes and returns the checksum of this token, computed using the passed key and key usage.
|
||||||
|
// Note: This will NOT update the struct's Checksum field.
|
||||||
|
func (wt *WrapToken) computeCheckSum(key types.EncryptionKey, keyUsage uint32) ([]byte, error) {
|
||||||
|
if wt.Payload == nil {
|
||||||
|
return nil, errors.New("cannot compute checksum with uninitialized payload")
|
||||||
|
}
|
||||||
|
// Build a slice containing { payload | header }
|
||||||
|
checksumMe := make([]byte, HdrLen+len(wt.Payload))
|
||||||
|
copy(checksumMe[0:], wt.Payload)
|
||||||
|
copy(checksumMe[len(wt.Payload):], getChecksumHeader(wt.Flags, wt.SndSeqNum))
|
||||||
|
|
||||||
|
encType, err := crypto.GetEtype(key.KeyType)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return encType.GetChecksumHash(key.KeyValue, checksumMe, keyUsage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build a header suitable for a checksum computation
|
||||||
|
func getChecksumHeader(flags byte, senderSeqNum uint64) []byte {
|
||||||
|
header := make([]byte, 16)
|
||||||
|
copy(header[0:], []byte{0x05, 0x04, flags, 0xFF, 0x00, 0x00, 0x00, 0x00})
|
||||||
|
binary.BigEndian.PutUint64(header[8:], senderSeqNum)
|
||||||
|
return header
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify computes the token's checksum with the provided key and usage,
|
||||||
|
// and compares it to the checksum present in the token.
|
||||||
|
// In case of any failure, (false, Err) is returned, with Err an explanatory error.
|
||||||
|
func (wt *WrapToken) Verify(key types.EncryptionKey, keyUsage uint32) (bool, error) {
|
||||||
|
computed, cErr := wt.computeCheckSum(key, keyUsage)
|
||||||
|
if cErr != nil {
|
||||||
|
return false, cErr
|
||||||
|
}
|
||||||
|
if !hmac.Equal(computed, wt.CheckSum) {
|
||||||
|
return false, fmt.Errorf(
|
||||||
|
"checksum mismatch. Computed: %s, Contained in token: %s",
|
||||||
|
hex.EncodeToString(computed), hex.EncodeToString(wt.CheckSum))
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshal bytes into the corresponding WrapToken.
|
||||||
|
// If expectFromAcceptor is true, we expect the token to have been emitted by the gss acceptor,
|
||||||
|
// and will check the according flag, returning an error if the token does not match the expectation.
|
||||||
|
func (wt *WrapToken) Unmarshal(b []byte, expectFromAcceptor bool) error {
|
||||||
|
// Check if we can read a whole header
|
||||||
|
if len(b) < 16 {
|
||||||
|
return errors.New("bytes shorter than header length")
|
||||||
|
}
|
||||||
|
// Is the Token ID correct?
|
||||||
|
if !bytes.Equal(getGssWrapTokenId()[:], b[0:2]) {
|
||||||
|
return fmt.Errorf("wrong Token ID. Expected %s, was %s",
|
||||||
|
hex.EncodeToString(getGssWrapTokenId()[:]),
|
||||||
|
hex.EncodeToString(b[0:2]))
|
||||||
|
}
|
||||||
|
// Check the acceptor flag
|
||||||
|
flags := b[2]
|
||||||
|
isFromAcceptor := flags&0x01 == 1
|
||||||
|
if isFromAcceptor && !expectFromAcceptor {
|
||||||
|
return errors.New("unexpected acceptor flag is set: not expecting a token from the acceptor")
|
||||||
|
}
|
||||||
|
if !isFromAcceptor && expectFromAcceptor {
|
||||||
|
return errors.New("expected acceptor flag is not set: expecting a token from the acceptor, not the initiator")
|
||||||
|
}
|
||||||
|
// Check the filler byte
|
||||||
|
if b[3] != FillerByte {
|
||||||
|
return fmt.Errorf("unexpected filler byte: expecting 0xFF, was %s ", hex.EncodeToString(b[3:4]))
|
||||||
|
}
|
||||||
|
checksumL := binary.BigEndian.Uint16(b[4:6])
|
||||||
|
// Sanity check on the checksum length
|
||||||
|
if int(checksumL) > len(b)-HdrLen {
|
||||||
|
return fmt.Errorf("inconsistent checksum length: %d bytes to parse, checksum length is %d", len(b), checksumL)
|
||||||
|
}
|
||||||
|
|
||||||
|
wt.Flags = flags
|
||||||
|
wt.EC = checksumL
|
||||||
|
wt.RRC = binary.BigEndian.Uint16(b[6:8])
|
||||||
|
wt.SndSeqNum = binary.BigEndian.Uint64(b[8:16])
|
||||||
|
wt.Payload = b[16 : len(b)-int(checksumL)]
|
||||||
|
wt.CheckSum = b[len(b)-int(checksumL):]
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewInitiatorWrapToken builds a new initiator token (acceptor flag will be set to 0) and computes the authenticated checksum.
|
||||||
|
// Other flags are set to 0, and the RRC and sequence number are initialized to 0.
|
||||||
|
// Note that in certain circumstances you may need to provide a sequence number that has been defined earlier.
|
||||||
|
// This is currently not supported.
|
||||||
|
func NewInitiatorWrapToken(payload []byte, key types.EncryptionKey) (*WrapToken, error) {
|
||||||
|
encType, err := crypto.GetEtype(key.KeyType)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
token := WrapToken{
|
||||||
|
Flags: 0x00, // all zeroed out (this is a token sent by the initiator)
|
||||||
|
// Checksum size: length of output of the HMAC function, in bytes.
|
||||||
|
EC: uint16(encType.GetHMACBitLength() / 8),
|
||||||
|
RRC: 0,
|
||||||
|
SndSeqNum: 0,
|
||||||
|
Payload: payload,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := token.SetCheckSum(key, keyusage.GSSAPI_INITIATOR_SEAL); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &token, nil
|
||||||
|
}
|
15
vendor/github.com/jcmturner/gokrb5/v8/iana/addrtype/constants.go
generated
vendored
Normal file
15
vendor/github.com/jcmturner/gokrb5/v8/iana/addrtype/constants.go
generated
vendored
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// Package addrtype provides Address type assigned numbers.
|
||||||
|
package addrtype
|
||||||
|
|
||||||
|
// Address type IDs.
|
||||||
|
const (
|
||||||
|
IPv4 int32 = 2
|
||||||
|
Directional int32 = 3
|
||||||
|
ChaosNet int32 = 5
|
||||||
|
XNS int32 = 6
|
||||||
|
ISO int32 = 7
|
||||||
|
DECNETPhaseIV int32 = 12
|
||||||
|
AppleTalkDDP int32 = 16
|
||||||
|
NetBios int32 = 20
|
||||||
|
IPv6 int32 = 24
|
||||||
|
)
|
23
vendor/github.com/jcmturner/gokrb5/v8/iana/adtype/constants.go
generated
vendored
Normal file
23
vendor/github.com/jcmturner/gokrb5/v8/iana/adtype/constants.go
generated
vendored
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
// Package adtype provides Authenticator type assigned numbers.
|
||||||
|
package adtype
|
||||||
|
|
||||||
|
// Authenticator type IDs.
|
||||||
|
const (
|
||||||
|
ADIfRelevant int32 = 1
|
||||||
|
ADIntendedForServer int32 = 2
|
||||||
|
ADIntendedForApplicationClass int32 = 3
|
||||||
|
ADKDCIssued int32 = 4
|
||||||
|
ADAndOr int32 = 5
|
||||||
|
ADMandatoryTicketExtensions int32 = 6
|
||||||
|
ADInTicketExtensions int32 = 7
|
||||||
|
ADMandatoryForKDC int32 = 8
|
||||||
|
OSFDCE int32 = 64
|
||||||
|
SESAME int32 = 65
|
||||||
|
ADOSFDCEPKICertID int32 = 66
|
||||||
|
ADAuthenticationStrength int32 = 70
|
||||||
|
ADFXFastArmor int32 = 71
|
||||||
|
ADFXFastUsed int32 = 72
|
||||||
|
ADWin2KPAC int32 = 128
|
||||||
|
ADEtypeNegotiation int32 = 129
|
||||||
|
//Reserved values 9-63
|
||||||
|
)
|
24
vendor/github.com/jcmturner/gokrb5/v8/iana/asnAppTag/constants.go
generated
vendored
Normal file
24
vendor/github.com/jcmturner/gokrb5/v8/iana/asnAppTag/constants.go
generated
vendored
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
// Package asnAppTag provides ASN1 application tag numbers.
|
||||||
|
package asnAppTag
|
||||||
|
|
||||||
|
// ASN1 application tag numbers.
|
||||||
|
const (
|
||||||
|
Ticket = 1
|
||||||
|
Authenticator = 2
|
||||||
|
EncTicketPart = 3
|
||||||
|
ASREQ = 10
|
||||||
|
TGSREQ = 12
|
||||||
|
ASREP = 11
|
||||||
|
TGSREP = 13
|
||||||
|
APREQ = 14
|
||||||
|
APREP = 15
|
||||||
|
KRBSafe = 20
|
||||||
|
KRBPriv = 21
|
||||||
|
KRBCred = 22
|
||||||
|
EncASRepPart = 25
|
||||||
|
EncTGSRepPart = 26
|
||||||
|
EncAPRepPart = 27
|
||||||
|
EncKrbPrivPart = 28
|
||||||
|
EncKrbCredPart = 29
|
||||||
|
KRBError = 30
|
||||||
|
)
|
32
vendor/github.com/jcmturner/gokrb5/v8/iana/chksumtype/constants.go
generated
vendored
Normal file
32
vendor/github.com/jcmturner/gokrb5/v8/iana/chksumtype/constants.go
generated
vendored
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
// Package chksumtype provides Kerberos 5 checksum type assigned numbers.
|
||||||
|
package chksumtype
|
||||||
|
|
||||||
|
// Checksum type IDs.
|
||||||
|
const (
|
||||||
|
//RESERVED : 0
|
||||||
|
CRC32 int32 = 1
|
||||||
|
RSA_MD4 int32 = 2
|
||||||
|
RSA_MD4_DES int32 = 3
|
||||||
|
DES_MAC int32 = 4
|
||||||
|
DES_MAC_K int32 = 5
|
||||||
|
RSA_MD4_DES_K int32 = 6
|
||||||
|
RSA_MD5 int32 = 7
|
||||||
|
RSA_MD5_DES int32 = 8
|
||||||
|
RSA_MD5_DES3 int32 = 9
|
||||||
|
SHA1_ID10 int32 = 10
|
||||||
|
//UNASSIGNED : 11
|
||||||
|
HMAC_SHA1_DES3_KD int32 = 12
|
||||||
|
HMAC_SHA1_DES3 int32 = 13
|
||||||
|
SHA1_ID14 int32 = 14
|
||||||
|
HMAC_SHA1_96_AES128 int32 = 15
|
||||||
|
HMAC_SHA1_96_AES256 int32 = 16
|
||||||
|
CMAC_CAMELLIA128 int32 = 17
|
||||||
|
CMAC_CAMELLIA256 int32 = 18
|
||||||
|
HMAC_SHA256_128_AES128 int32 = 19
|
||||||
|
HMAC_SHA384_192_AES256 int32 = 20
|
||||||
|
//UNASSIGNED : 21-32770
|
||||||
|
GSSAPI int32 = 32771
|
||||||
|
//UNASSIGNED : 32772-2147483647
|
||||||
|
KERB_CHECKSUM_HMAC_MD5_UNSIGNED uint32 = 4294967158 // 0xFFFFFF76 documentation says this is -138 but in an unsigned int this is 4294967158
|
||||||
|
KERB_CHECKSUM_HMAC_MD5 int32 = -138
|
||||||
|
)
|
5
vendor/github.com/jcmturner/gokrb5/v8/iana/constants.go
generated
vendored
Normal file
5
vendor/github.com/jcmturner/gokrb5/v8/iana/constants.go
generated
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
// Package iana provides Kerberos 5 assigned numbers.
|
||||||
|
package iana
|
||||||
|
|
||||||
|
// PVNO is the Protocol Version Number.
|
||||||
|
const PVNO = 5
|
155
vendor/github.com/jcmturner/gokrb5/v8/iana/errorcode/constants.go
generated
vendored
Normal file
155
vendor/github.com/jcmturner/gokrb5/v8/iana/errorcode/constants.go
generated
vendored
Normal file
|
@ -0,0 +1,155 @@
|
||||||
|
// Package errorcode provides Kerberos 5 assigned error codes.
|
||||||
|
package errorcode
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
// Kerberos error codes.
|
||||||
|
const (
|
||||||
|
KDC_ERR_NONE int32 = 0 //No error
|
||||||
|
KDC_ERR_NAME_EXP int32 = 1 //Client's entry in database has expired
|
||||||
|
KDC_ERR_SERVICE_EXP int32 = 2 //Server's entry in database has expired
|
||||||
|
KDC_ERR_BAD_PVNO int32 = 3 //Requested protocol version number not supported
|
||||||
|
KDC_ERR_C_OLD_MAST_KVNO int32 = 4 //Client's key encrypted in old master key
|
||||||
|
KDC_ERR_S_OLD_MAST_KVNO int32 = 5 //Server's key encrypted in old master key
|
||||||
|
KDC_ERR_C_PRINCIPAL_UNKNOWN int32 = 6 //Client not found in Kerberos database
|
||||||
|
KDC_ERR_S_PRINCIPAL_UNKNOWN int32 = 7 //Server not found in Kerberos database
|
||||||
|
KDC_ERR_PRINCIPAL_NOT_UNIQUE int32 = 8 //Multiple principal entries in database
|
||||||
|
KDC_ERR_NULL_KEY int32 = 9 //The client or server has a null key
|
||||||
|
KDC_ERR_CANNOT_POSTDATE int32 = 10 //Ticket not eligible for postdating
|
||||||
|
KDC_ERR_NEVER_VALID int32 = 11 //Requested starttime is later than end time
|
||||||
|
KDC_ERR_POLICY int32 = 12 //KDC policy rejects request
|
||||||
|
KDC_ERR_BADOPTION int32 = 13 //KDC cannot accommodate requested option
|
||||||
|
KDC_ERR_ETYPE_NOSUPP int32 = 14 //KDC has no support for encryption type
|
||||||
|
KDC_ERR_SUMTYPE_NOSUPP int32 = 15 //KDC has no support for checksum type
|
||||||
|
KDC_ERR_PADATA_TYPE_NOSUPP int32 = 16 //KDC has no support for padata type
|
||||||
|
KDC_ERR_TRTYPE_NOSUPP int32 = 17 //KDC has no support for transited type
|
||||||
|
KDC_ERR_CLIENT_REVOKED int32 = 18 //Clients credentials have been revoked
|
||||||
|
KDC_ERR_SERVICE_REVOKED int32 = 19 //Credentials for server have been revoked
|
||||||
|
KDC_ERR_TGT_REVOKED int32 = 20 //TGT has been revoked
|
||||||
|
KDC_ERR_CLIENT_NOTYET int32 = 21 //Client not yet valid; try again later
|
||||||
|
KDC_ERR_SERVICE_NOTYET int32 = 22 //Server not yet valid; try again later
|
||||||
|
KDC_ERR_KEY_EXPIRED int32 = 23 //Password has expired; change password to reset
|
||||||
|
KDC_ERR_PREAUTH_FAILED int32 = 24 //Pre-authentication information was invalid
|
||||||
|
KDC_ERR_PREAUTH_REQUIRED int32 = 25 //Additional pre-authentication required
|
||||||
|
KDC_ERR_SERVER_NOMATCH int32 = 26 //Requested server and ticket don't match
|
||||||
|
KDC_ERR_MUST_USE_USER2USER int32 = 27 //Server principal valid for user2user only
|
||||||
|
KDC_ERR_PATH_NOT_ACCEPTED int32 = 28 //KDC Policy rejects transited path
|
||||||
|
KDC_ERR_SVC_UNAVAILABLE int32 = 29 //A service is not available
|
||||||
|
KRB_AP_ERR_BAD_INTEGRITY int32 = 31 //Integrity check on decrypted field failed
|
||||||
|
KRB_AP_ERR_TKT_EXPIRED int32 = 32 //Ticket expired
|
||||||
|
KRB_AP_ERR_TKT_NYV int32 = 33 //Ticket not yet valid
|
||||||
|
KRB_AP_ERR_REPEAT int32 = 34 //Request is a replay
|
||||||
|
KRB_AP_ERR_NOT_US int32 = 35 //The ticket isn't for us
|
||||||
|
KRB_AP_ERR_BADMATCH int32 = 36 //Ticket and authenticator don't match
|
||||||
|
KRB_AP_ERR_SKEW int32 = 37 //Clock skew too great
|
||||||
|
KRB_AP_ERR_BADADDR int32 = 38 //Incorrect net address
|
||||||
|
KRB_AP_ERR_BADVERSION int32 = 39 //Protocol version mismatch
|
||||||
|
KRB_AP_ERR_MSG_TYPE int32 = 40 //Invalid msg type
|
||||||
|
KRB_AP_ERR_MODIFIED int32 = 41 //Message stream modified
|
||||||
|
KRB_AP_ERR_BADORDER int32 = 42 //Message out of order
|
||||||
|
KRB_AP_ERR_BADKEYVER int32 = 44 //Specified version of key is not available
|
||||||
|
KRB_AP_ERR_NOKEY int32 = 45 //Service key not available
|
||||||
|
KRB_AP_ERR_MUT_FAIL int32 = 46 //Mutual authentication failed
|
||||||
|
KRB_AP_ERR_BADDIRECTION int32 = 47 //Incorrect message direction
|
||||||
|
KRB_AP_ERR_METHOD int32 = 48 //Alternative authentication method required
|
||||||
|
KRB_AP_ERR_BADSEQ int32 = 49 //Incorrect sequence number in message
|
||||||
|
KRB_AP_ERR_INAPP_CKSUM int32 = 50 //Inappropriate type of checksum in message
|
||||||
|
KRB_AP_PATH_NOT_ACCEPTED int32 = 51 //Policy rejects transited path
|
||||||
|
KRB_ERR_RESPONSE_TOO_BIG int32 = 52 //Response too big for UDP; retry with TCP
|
||||||
|
KRB_ERR_GENERIC int32 = 60 //Generic error (description in e-text)
|
||||||
|
KRB_ERR_FIELD_TOOLONG int32 = 61 //Field is too long for this implementation
|
||||||
|
KDC_ERROR_CLIENT_NOT_TRUSTED int32 = 62 //Reserved for PKINIT
|
||||||
|
KDC_ERROR_KDC_NOT_TRUSTED int32 = 63 //Reserved for PKINIT
|
||||||
|
KDC_ERROR_INVALID_SIG int32 = 64 //Reserved for PKINIT
|
||||||
|
KDC_ERR_KEY_TOO_WEAK int32 = 65 //Reserved for PKINIT
|
||||||
|
KDC_ERR_CERTIFICATE_MISMATCH int32 = 66 //Reserved for PKINIT
|
||||||
|
KRB_AP_ERR_NO_TGT int32 = 67 //No TGT available to validate USER-TO-USER
|
||||||
|
KDC_ERR_WRONG_REALM int32 = 68 //Reserved for future use
|
||||||
|
KRB_AP_ERR_USER_TO_USER_REQUIRED int32 = 69 //Ticket must be for USER-TO-USER
|
||||||
|
KDC_ERR_CANT_VERIFY_CERTIFICATE int32 = 70 //Reserved for PKINIT
|
||||||
|
KDC_ERR_INVALID_CERTIFICATE int32 = 71 //Reserved for PKINIT
|
||||||
|
KDC_ERR_REVOKED_CERTIFICATE int32 = 72 //Reserved for PKINIT
|
||||||
|
KDC_ERR_REVOCATION_STATUS_UNKNOWN int32 = 73 //Reserved for PKINIT
|
||||||
|
KDC_ERR_REVOCATION_STATUS_UNAVAILABLE int32 = 74 //Reserved for PKINIT
|
||||||
|
KDC_ERR_CLIENT_NAME_MISMATCH int32 = 75 //Reserved for PKINIT
|
||||||
|
KDC_ERR_KDC_NAME_MISMATCH int32 = 76 //Reserved for PKINIT
|
||||||
|
)
|
||||||
|
|
||||||
|
// Lookup an error code description.
|
||||||
|
func Lookup(i int32) string {
|
||||||
|
if s, ok := errorcodeLookup[i]; ok {
|
||||||
|
return fmt.Sprintf("(%d) %s", i, s)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("Unknown ErrorCode %d", i)
|
||||||
|
}
|
||||||
|
|
||||||
|
var errorcodeLookup = map[int32]string{
|
||||||
|
KDC_ERR_NONE: "KDC_ERR_NONE No error",
|
||||||
|
KDC_ERR_NAME_EXP: "KDC_ERR_NAME_EXP Client's entry in database has expired",
|
||||||
|
KDC_ERR_SERVICE_EXP: "KDC_ERR_SERVICE_EXP Server's entry in database has expired",
|
||||||
|
KDC_ERR_BAD_PVNO: "KDC_ERR_BAD_PVNO Requested protocol version number not supported",
|
||||||
|
KDC_ERR_C_OLD_MAST_KVNO: "KDC_ERR_C_OLD_MAST_KVNO Client's key encrypted in old master key",
|
||||||
|
KDC_ERR_S_OLD_MAST_KVNO: "KDC_ERR_S_OLD_MAST_KVNO Server's key encrypted in old master key",
|
||||||
|
KDC_ERR_C_PRINCIPAL_UNKNOWN: "KDC_ERR_C_PRINCIPAL_UNKNOWN Client not found in Kerberos database",
|
||||||
|
KDC_ERR_S_PRINCIPAL_UNKNOWN: "KDC_ERR_S_PRINCIPAL_UNKNOWN Server not found in Kerberos database",
|
||||||
|
KDC_ERR_PRINCIPAL_NOT_UNIQUE: "KDC_ERR_PRINCIPAL_NOT_UNIQUE Multiple principal entries in database",
|
||||||
|
KDC_ERR_NULL_KEY: "KDC_ERR_NULL_KEY The client or server has a null key",
|
||||||
|
KDC_ERR_CANNOT_POSTDATE: "KDC_ERR_CANNOT_POSTDATE Ticket not eligible for postdating",
|
||||||
|
KDC_ERR_NEVER_VALID: "KDC_ERR_NEVER_VALID Requested starttime is later than end time",
|
||||||
|
KDC_ERR_POLICY: "KDC_ERR_POLICY KDC policy rejects request",
|
||||||
|
KDC_ERR_BADOPTION: "KDC_ERR_BADOPTION KDC cannot accommodate requested option",
|
||||||
|
KDC_ERR_ETYPE_NOSUPP: "KDC_ERR_ETYPE_NOSUPP KDC has no support for encryption type",
|
||||||
|
KDC_ERR_SUMTYPE_NOSUPP: "KDC_ERR_SUMTYPE_NOSUPP KDC has no support for checksum type",
|
||||||
|
KDC_ERR_PADATA_TYPE_NOSUPP: "KDC_ERR_PADATA_TYPE_NOSUPP KDC has no support for padata type",
|
||||||
|
KDC_ERR_TRTYPE_NOSUPP: "KDC_ERR_TRTYPE_NOSUPP KDC has no support for transited type",
|
||||||
|
KDC_ERR_CLIENT_REVOKED: "KDC_ERR_CLIENT_REVOKED Clients credentials have been revoked",
|
||||||
|
KDC_ERR_SERVICE_REVOKED: "KDC_ERR_SERVICE_REVOKED Credentials for server have been revoked",
|
||||||
|
KDC_ERR_TGT_REVOKED: "KDC_ERR_TGT_REVOKED TGT has been revoked",
|
||||||
|
KDC_ERR_CLIENT_NOTYET: "KDC_ERR_CLIENT_NOTYET Client not yet valid; try again later",
|
||||||
|
KDC_ERR_SERVICE_NOTYET: "KDC_ERR_SERVICE_NOTYET Server not yet valid; try again later",
|
||||||
|
KDC_ERR_KEY_EXPIRED: "KDC_ERR_KEY_EXPIRED Password has expired; change password to reset",
|
||||||
|
KDC_ERR_PREAUTH_FAILED: "KDC_ERR_PREAUTH_FAILED Pre-authentication information was invalid",
|
||||||
|
KDC_ERR_PREAUTH_REQUIRED: "KDC_ERR_PREAUTH_REQUIRED Additional pre-authentication required",
|
||||||
|
KDC_ERR_SERVER_NOMATCH: "KDC_ERR_SERVER_NOMATCH Requested server and ticket don't match",
|
||||||
|
KDC_ERR_MUST_USE_USER2USER: "KDC_ERR_MUST_USE_USER2USER Server principal valid for user2user only",
|
||||||
|
KDC_ERR_PATH_NOT_ACCEPTED: "KDC_ERR_PATH_NOT_ACCEPTED KDC Policy rejects transited path",
|
||||||
|
KDC_ERR_SVC_UNAVAILABLE: "KDC_ERR_SVC_UNAVAILABLE A service is not available",
|
||||||
|
KRB_AP_ERR_BAD_INTEGRITY: "KRB_AP_ERR_BAD_INTEGRITY Integrity check on decrypted field failed",
|
||||||
|
KRB_AP_ERR_TKT_EXPIRED: "KRB_AP_ERR_TKT_EXPIRED Ticket expired",
|
||||||
|
KRB_AP_ERR_TKT_NYV: "KRB_AP_ERR_TKT_NYV Ticket not yet valid",
|
||||||
|
KRB_AP_ERR_REPEAT: "KRB_AP_ERR_REPEAT Request is a replay",
|
||||||
|
KRB_AP_ERR_NOT_US: "KRB_AP_ERR_NOT_US The ticket isn't for us",
|
||||||
|
KRB_AP_ERR_BADMATCH: "KRB_AP_ERR_BADMATCH Ticket and authenticator don't match",
|
||||||
|
KRB_AP_ERR_SKEW: "KRB_AP_ERR_SKEW Clock skew too great",
|
||||||
|
KRB_AP_ERR_BADADDR: "KRB_AP_ERR_BADADDR Incorrect net address",
|
||||||
|
KRB_AP_ERR_BADVERSION: "KRB_AP_ERR_BADVERSION Protocol version mismatch",
|
||||||
|
KRB_AP_ERR_MSG_TYPE: "KRB_AP_ERR_MSG_TYPE Invalid msg type",
|
||||||
|
KRB_AP_ERR_MODIFIED: "KRB_AP_ERR_MODIFIED Message stream modified",
|
||||||
|
KRB_AP_ERR_BADORDER: "KRB_AP_ERR_BADORDER Message out of order",
|
||||||
|
KRB_AP_ERR_BADKEYVER: "KRB_AP_ERR_BADKEYVER Specified version of key is not available",
|
||||||
|
KRB_AP_ERR_NOKEY: "KRB_AP_ERR_NOKEY Service key not available",
|
||||||
|
KRB_AP_ERR_MUT_FAIL: "KRB_AP_ERR_MUT_FAIL Mutual authentication failed",
|
||||||
|
KRB_AP_ERR_BADDIRECTION: "KRB_AP_ERR_BADDIRECTION Incorrect message direction",
|
||||||
|
KRB_AP_ERR_METHOD: "KRB_AP_ERR_METHOD Alternative authentication method required",
|
||||||
|
KRB_AP_ERR_BADSEQ: "KRB_AP_ERR_BADSEQ Incorrect sequence number in message",
|
||||||
|
KRB_AP_ERR_INAPP_CKSUM: "KRB_AP_ERR_INAPP_CKSUM Inappropriate type of checksum in message",
|
||||||
|
KRB_AP_PATH_NOT_ACCEPTED: "KRB_AP_PATH_NOT_ACCEPTED Policy rejects transited path",
|
||||||
|
KRB_ERR_RESPONSE_TOO_BIG: "KRB_ERR_RESPONSE_TOO_BIG Response too big for UDP; retry with TCP",
|
||||||
|
KRB_ERR_GENERIC: "KRB_ERR_GENERIC Generic error (description in e-text)",
|
||||||
|
KRB_ERR_FIELD_TOOLONG: "KRB_ERR_FIELD_TOOLONG Field is too long for this implementation",
|
||||||
|
KDC_ERROR_CLIENT_NOT_TRUSTED: "KDC_ERROR_CLIENT_NOT_TRUSTED Reserved for PKINIT",
|
||||||
|
KDC_ERROR_KDC_NOT_TRUSTED: "KDC_ERROR_KDC_NOT_TRUSTED Reserved for PKINIT",
|
||||||
|
KDC_ERROR_INVALID_SIG: "KDC_ERROR_INVALID_SIG Reserved for PKINIT",
|
||||||
|
KDC_ERR_KEY_TOO_WEAK: "KDC_ERR_KEY_TOO_WEAK Reserved for PKINIT",
|
||||||
|
KDC_ERR_CERTIFICATE_MISMATCH: "KDC_ERR_CERTIFICATE_MISMATCH Reserved for PKINIT",
|
||||||
|
KRB_AP_ERR_NO_TGT: "KRB_AP_ERR_NO_TGT No TGT available to validate USER-TO-USER",
|
||||||
|
KDC_ERR_WRONG_REALM: "KDC_ERR_WRONG_REALM Reserved for future use",
|
||||||
|
KRB_AP_ERR_USER_TO_USER_REQUIRED: "KRB_AP_ERR_USER_TO_USER_REQUIRED Ticket must be for USER-TO-USER",
|
||||||
|
KDC_ERR_CANT_VERIFY_CERTIFICATE: "KDC_ERR_CANT_VERIFY_CERTIFICATE Reserved for PKINIT",
|
||||||
|
KDC_ERR_INVALID_CERTIFICATE: "KDC_ERR_INVALID_CERTIFICATE Reserved for PKINIT",
|
||||||
|
KDC_ERR_REVOKED_CERTIFICATE: "KDC_ERR_REVOKED_CERTIFICATE Reserved for PKINIT",
|
||||||
|
KDC_ERR_REVOCATION_STATUS_UNKNOWN: "KDC_ERR_REVOCATION_STATUS_UNKNOWN Reserved for PKINIT",
|
||||||
|
KDC_ERR_REVOCATION_STATUS_UNAVAILABLE: "KDC_ERR_REVOCATION_STATUS_UNAVAILABLE Reserved for PKINIT",
|
||||||
|
KDC_ERR_CLIENT_NAME_MISMATCH: "KDC_ERR_CLIENT_NAME_MISMATCH Reserved for PKINIT",
|
||||||
|
KDC_ERR_KDC_NAME_MISMATCH: "KDC_ERR_KDC_NAME_MISMATCH Reserved for PKINIT",
|
||||||
|
}
|
101
vendor/github.com/jcmturner/gokrb5/v8/iana/etypeID/constants.go
generated
vendored
Normal file
101
vendor/github.com/jcmturner/gokrb5/v8/iana/etypeID/constants.go
generated
vendored
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
// Package etypeID provides Kerberos 5 encryption type assigned numbers.
|
||||||
|
package etypeID
|
||||||
|
|
||||||
|
// Kerberos encryption type assigned numbers.
|
||||||
|
const (
|
||||||
|
//RESERVED : 0
|
||||||
|
DES_CBC_CRC int32 = 1
|
||||||
|
DES_CBC_MD4 int32 = 2
|
||||||
|
DES_CBC_MD5 int32 = 3
|
||||||
|
DES_CBC_RAW int32 = 4
|
||||||
|
DES3_CBC_MD5 int32 = 5
|
||||||
|
DES3_CBC_RAW int32 = 6
|
||||||
|
DES3_CBC_SHA1 int32 = 7
|
||||||
|
DES_HMAC_SHA1 int32 = 8
|
||||||
|
DSAWITHSHA1_CMSOID int32 = 9
|
||||||
|
MD5WITHRSAENCRYPTION_CMSOID int32 = 10
|
||||||
|
SHA1WITHRSAENCRYPTION_CMSOID int32 = 11
|
||||||
|
RC2CBC_ENVOID int32 = 12
|
||||||
|
RSAENCRYPTION_ENVOID int32 = 13
|
||||||
|
RSAES_OAEP_ENV_OID int32 = 14
|
||||||
|
DES_EDE3_CBC_ENV_OID int32 = 15
|
||||||
|
DES3_CBC_SHA1_KD int32 = 16
|
||||||
|
AES128_CTS_HMAC_SHA1_96 int32 = 17
|
||||||
|
AES256_CTS_HMAC_SHA1_96 int32 = 18
|
||||||
|
AES128_CTS_HMAC_SHA256_128 int32 = 19
|
||||||
|
AES256_CTS_HMAC_SHA384_192 int32 = 20
|
||||||
|
//UNASSIGNED : 21-22
|
||||||
|
RC4_HMAC int32 = 23
|
||||||
|
RC4_HMAC_EXP int32 = 24
|
||||||
|
CAMELLIA128_CTS_CMAC int32 = 25
|
||||||
|
CAMELLIA256_CTS_CMAC int32 = 26
|
||||||
|
//UNASSIGNED : 27-64
|
||||||
|
SUBKEY_KEYMATERIAL int32 = 65
|
||||||
|
//UNASSIGNED : 66-2147483647
|
||||||
|
)
|
||||||
|
|
||||||
|
// ETypesByName is a map of EncType names to their assigned EncType number.
|
||||||
|
var ETypesByName = map[string]int32{
|
||||||
|
"des-cbc-crc": DES_CBC_CRC,
|
||||||
|
"des-cbc-md4": DES_CBC_MD4,
|
||||||
|
"des-cbc-md5": DES_CBC_MD5,
|
||||||
|
"des-cbc-raw": DES_CBC_RAW,
|
||||||
|
"des3-cbc-md5": DES3_CBC_MD5,
|
||||||
|
"des3-cbc-raw": DES3_CBC_RAW,
|
||||||
|
"des3-cbc-sha1": DES3_CBC_SHA1,
|
||||||
|
"des3-hmac-sha1": DES_HMAC_SHA1,
|
||||||
|
"des3-cbc-sha1-kd": DES3_CBC_SHA1_KD,
|
||||||
|
"des-hmac-sha1": DES_HMAC_SHA1,
|
||||||
|
"dsaWithSHA1-CmsOID": DSAWITHSHA1_CMSOID,
|
||||||
|
"md5WithRSAEncryption-CmsOID": MD5WITHRSAENCRYPTION_CMSOID,
|
||||||
|
"sha1WithRSAEncryption-CmsOID": SHA1WITHRSAENCRYPTION_CMSOID,
|
||||||
|
"rc2CBC-EnvOID": RC2CBC_ENVOID,
|
||||||
|
"rsaEncryption-EnvOID": RSAENCRYPTION_ENVOID,
|
||||||
|
"rsaES-OAEP-ENV-OID": RSAES_OAEP_ENV_OID,
|
||||||
|
"des-ede3-cbc-Env-OID": DES_EDE3_CBC_ENV_OID,
|
||||||
|
"aes128-cts-hmac-sha1-96": AES128_CTS_HMAC_SHA1_96,
|
||||||
|
"aes128-cts": AES128_CTS_HMAC_SHA1_96,
|
||||||
|
"aes128-sha1": AES128_CTS_HMAC_SHA1_96,
|
||||||
|
"aes256-cts-hmac-sha1-96": AES256_CTS_HMAC_SHA1_96,
|
||||||
|
"aes256-cts": AES256_CTS_HMAC_SHA1_96,
|
||||||
|
"aes256-sha1": AES256_CTS_HMAC_SHA1_96,
|
||||||
|
"aes128-cts-hmac-sha256-128": AES128_CTS_HMAC_SHA256_128,
|
||||||
|
"aes128-sha2": AES128_CTS_HMAC_SHA256_128,
|
||||||
|
"aes256-cts-hmac-sha384-192": AES256_CTS_HMAC_SHA384_192,
|
||||||
|
"aes256-sha2": AES256_CTS_HMAC_SHA384_192,
|
||||||
|
"arcfour-hmac": RC4_HMAC,
|
||||||
|
"rc4-hmac": RC4_HMAC,
|
||||||
|
"arcfour-hmac-md5": RC4_HMAC,
|
||||||
|
"arcfour-hmac-exp": RC4_HMAC_EXP,
|
||||||
|
"rc4-hmac-exp": RC4_HMAC_EXP,
|
||||||
|
"arcfour-hmac-md5-exp": RC4_HMAC_EXP,
|
||||||
|
"camellia128-cts-cmac": CAMELLIA128_CTS_CMAC,
|
||||||
|
"camellia128-cts": CAMELLIA128_CTS_CMAC,
|
||||||
|
"camellia256-cts-cmac": CAMELLIA256_CTS_CMAC,
|
||||||
|
"camellia256-cts": CAMELLIA256_CTS_CMAC,
|
||||||
|
"subkey-keymaterial": SUBKEY_KEYMATERIAL,
|
||||||
|
}
|
||||||
|
|
||||||
|
// EtypeSupported resolves the etype name string to the etype ID.
|
||||||
|
// If zero is returned the etype is not supported by gokrb5.
|
||||||
|
func EtypeSupported(etype string) int32 {
|
||||||
|
// Slice of supported enctype IDs
|
||||||
|
s := []int32{
|
||||||
|
AES128_CTS_HMAC_SHA1_96,
|
||||||
|
AES256_CTS_HMAC_SHA1_96,
|
||||||
|
AES128_CTS_HMAC_SHA256_128,
|
||||||
|
AES256_CTS_HMAC_SHA384_192,
|
||||||
|
DES3_CBC_SHA1_KD,
|
||||||
|
RC4_HMAC,
|
||||||
|
}
|
||||||
|
id := ETypesByName[etype]
|
||||||
|
if id == 0 {
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
for _, sid := range s {
|
||||||
|
if id == sid {
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
36
vendor/github.com/jcmturner/gokrb5/v8/iana/flags/constants.go
generated
vendored
Normal file
36
vendor/github.com/jcmturner/gokrb5/v8/iana/flags/constants.go
generated
vendored
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
// Package flags provides Kerberos 5 flag assigned numbers.
|
||||||
|
package flags
|
||||||
|
|
||||||
|
// Flag values for KRB5 messages and tickets.
|
||||||
|
const (
|
||||||
|
Reserved = 0
|
||||||
|
Forwardable = 1
|
||||||
|
Forwarded = 2
|
||||||
|
Proxiable = 3
|
||||||
|
Proxy = 4
|
||||||
|
AllowPostDate = 5
|
||||||
|
MayPostDate = 5
|
||||||
|
PostDated = 6
|
||||||
|
Invalid = 7
|
||||||
|
Renewable = 8
|
||||||
|
Initial = 9
|
||||||
|
PreAuthent = 10
|
||||||
|
HWAuthent = 11
|
||||||
|
OptHardwareAuth = 11
|
||||||
|
RequestAnonymous = 12
|
||||||
|
TransitedPolicyChecked = 12
|
||||||
|
OKAsDelegate = 13
|
||||||
|
EncPARep = 15
|
||||||
|
Canonicalize = 15
|
||||||
|
DisableTransitedCheck = 26
|
||||||
|
RenewableOK = 27
|
||||||
|
EncTktInSkey = 28
|
||||||
|
Renew = 30
|
||||||
|
Validate = 31
|
||||||
|
|
||||||
|
// AP Option Flags
|
||||||
|
// 0 Reserved for future use.
|
||||||
|
APOptionUseSessionKey = 1
|
||||||
|
APOptionMutualRequired = 2
|
||||||
|
// 3-31 Reserved for future use.
|
||||||
|
)
|
42
vendor/github.com/jcmturner/gokrb5/v8/iana/keyusage/constants.go
generated
vendored
Normal file
42
vendor/github.com/jcmturner/gokrb5/v8/iana/keyusage/constants.go
generated
vendored
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
// Package keyusage provides Kerberos 5 key usage assigned numbers.
|
||||||
|
package keyusage
|
||||||
|
|
||||||
|
// Key usage numbers.
|
||||||
|
const (
|
||||||
|
AS_REQ_PA_ENC_TIMESTAMP = 1
|
||||||
|
KDC_REP_TICKET = 2
|
||||||
|
AS_REP_ENCPART = 3
|
||||||
|
TGS_REQ_KDC_REQ_BODY_AUTHDATA_SESSION_KEY = 4
|
||||||
|
TGS_REQ_KDC_REQ_BODY_AUTHDATA_SUB_KEY = 5
|
||||||
|
TGS_REQ_PA_TGS_REQ_AP_REQ_AUTHENTICATOR_CHKSUM = 6
|
||||||
|
TGS_REQ_PA_TGS_REQ_AP_REQ_AUTHENTICATOR = 7
|
||||||
|
TGS_REP_ENCPART_SESSION_KEY = 8
|
||||||
|
TGS_REP_ENCPART_AUTHENTICATOR_SUB_KEY = 9
|
||||||
|
AP_REQ_AUTHENTICATOR_CHKSUM = 10
|
||||||
|
AP_REQ_AUTHENTICATOR = 11
|
||||||
|
AP_REP_ENCPART = 12
|
||||||
|
KRB_PRIV_ENCPART = 13
|
||||||
|
KRB_CRED_ENCPART = 14
|
||||||
|
KRB_SAFE_CHKSUM = 15
|
||||||
|
KERB_NON_KERB_SALT = 16
|
||||||
|
KERB_NON_KERB_CKSUM_SALT = 17
|
||||||
|
//18. Reserved for future use in Kerberos and related protocols.
|
||||||
|
AD_KDC_ISSUED_CHKSUM = 19
|
||||||
|
//20-21. Reserved for future use in Kerberos and related protocols.
|
||||||
|
GSSAPI_ACCEPTOR_SEAL = 22
|
||||||
|
GSSAPI_ACCEPTOR_SIGN = 23
|
||||||
|
GSSAPI_INITIATOR_SEAL = 24
|
||||||
|
GSSAPI_INITIATOR_SIGN = 25
|
||||||
|
KEY_USAGE_FAST_REQ_CHKSUM = 50
|
||||||
|
KEY_USAGE_FAST_ENC = 51
|
||||||
|
KEY_USAGE_FAST_REP = 52
|
||||||
|
KEY_USAGE_FAST_FINISHED = 53
|
||||||
|
KEY_USAGE_ENC_CHALLENGE_CLIENT = 54
|
||||||
|
KEY_USAGE_ENC_CHALLENGE_KDC = 55
|
||||||
|
KEY_USAGE_AS_REQ = 56
|
||||||
|
//26-511. Reserved for future use in Kerberos and related protocols.
|
||||||
|
//512-1023. Reserved for uses internal to a Kerberos implementation.
|
||||||
|
//1024. Encryption for application use in protocols that do not specify key usage values
|
||||||
|
//1025. Checksums for application use in protocols that do not specify key usage values
|
||||||
|
//1026-2047. Reserved for application use.
|
||||||
|
)
|
18
vendor/github.com/jcmturner/gokrb5/v8/iana/msgtype/constants.go
generated
vendored
Normal file
18
vendor/github.com/jcmturner/gokrb5/v8/iana/msgtype/constants.go
generated
vendored
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
// Package msgtype provides Kerberos 5 message type assigned numbers.
|
||||||
|
package msgtype
|
||||||
|
|
||||||
|
// KRB message type IDs.
|
||||||
|
const (
|
||||||
|
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_RESERVED16 = 16 //Reserved for user-to-user krb_tgt_request
|
||||||
|
KRB_RESERVED17 = 17 //Reserved for user-to-user krb_tgt_reply
|
||||||
|
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
|
||||||
|
)
|
15
vendor/github.com/jcmturner/gokrb5/v8/iana/nametype/constants.go
generated
vendored
Normal file
15
vendor/github.com/jcmturner/gokrb5/v8/iana/nametype/constants.go
generated
vendored
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// Package nametype provides Kerberos 5 principal name type numbers.
|
||||||
|
package nametype
|
||||||
|
|
||||||
|
// Kerberos name type IDs.
|
||||||
|
const (
|
||||||
|
KRB_NT_UNKNOWN int32 = 0 //Name type not known
|
||||||
|
KRB_NT_PRINCIPAL int32 = 1 //Just the name of the principal as in DCE, or for users
|
||||||
|
KRB_NT_SRV_INST int32 = 2 //Service and other unique instance (krbtgt)
|
||||||
|
KRB_NT_SRV_HST int32 = 3 //Service with host name as instance (telnet, rcommands)
|
||||||
|
KRB_NT_SRV_XHST int32 = 4 //Service with host as remaining components
|
||||||
|
KRB_NT_UID int32 = 5 //Unique ID
|
||||||
|
KRB_NT_X500_PRINCIPAL int32 = 6 //Encoded X.509 Distinguished name [RFC2253]
|
||||||
|
KRB_NT_SMTP_NAME int32 = 7 //Name in form of SMTP email name (e.g., user@example.com)
|
||||||
|
KRB_NT_ENTERPRISE int32 = 10 //Enterprise name; may be mapped to principal name
|
||||||
|
)
|
77
vendor/github.com/jcmturner/gokrb5/v8/iana/patype/constants.go
generated
vendored
Normal file
77
vendor/github.com/jcmturner/gokrb5/v8/iana/patype/constants.go
generated
vendored
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
// Package patype provides Kerberos 5 pre-authentication type assigned numbers.
|
||||||
|
package patype
|
||||||
|
|
||||||
|
// Kerberos pre-authentication type assigned numbers.
|
||||||
|
const (
|
||||||
|
PA_TGS_REQ int32 = 1
|
||||||
|
PA_ENC_TIMESTAMP int32 = 2
|
||||||
|
PA_PW_SALT int32 = 3
|
||||||
|
//RESERVED : 4
|
||||||
|
PA_ENC_UNIX_TIME int32 = 5
|
||||||
|
PA_SANDIA_SECUREID int32 = 6
|
||||||
|
PA_SESAME int32 = 7
|
||||||
|
PA_OSF_DCE int32 = 8
|
||||||
|
PA_CYBERSAFE_SECUREID int32 = 9
|
||||||
|
PA_AFS3_SALT int32 = 10
|
||||||
|
PA_ETYPE_INFO int32 = 11
|
||||||
|
PA_SAM_CHALLENGE int32 = 12
|
||||||
|
PA_SAM_RESPONSE int32 = 13
|
||||||
|
PA_PK_AS_REQ_OLD int32 = 14
|
||||||
|
PA_PK_AS_REP_OLD int32 = 15
|
||||||
|
PA_PK_AS_REQ int32 = 16
|
||||||
|
PA_PK_AS_REP int32 = 17
|
||||||
|
PA_PK_OCSP_RESPONSE int32 = 18
|
||||||
|
PA_ETYPE_INFO2 int32 = 19
|
||||||
|
PA_USE_SPECIFIED_KVNO int32 = 20
|
||||||
|
PA_SVR_REFERRAL_INFO int32 = 20
|
||||||
|
PA_SAM_REDIRECT int32 = 21
|
||||||
|
PA_GET_FROM_TYPED_DATA int32 = 22
|
||||||
|
TD_PADATA int32 = 22
|
||||||
|
PA_SAM_ETYPE_INFO int32 = 23
|
||||||
|
PA_ALT_PRINC int32 = 24
|
||||||
|
PA_SERVER_REFERRAL int32 = 25
|
||||||
|
//UNASSIGNED : 26-29
|
||||||
|
PA_SAM_CHALLENGE2 int32 = 30
|
||||||
|
PA_SAM_RESPONSE2 int32 = 31
|
||||||
|
//UNASSIGNED : 32-40
|
||||||
|
PA_EXTRA_TGT int32 = 41
|
||||||
|
//UNASSIGNED : 42-100
|
||||||
|
TD_PKINIT_CMS_CERTIFICATES int32 = 101
|
||||||
|
TD_KRB_PRINCIPAL int32 = 102
|
||||||
|
TD_KRB_REALM int32 = 103
|
||||||
|
TD_TRUSTED_CERTIFIERS int32 = 104
|
||||||
|
TD_CERTIFICATE_INDEX int32 = 105
|
||||||
|
TD_APP_DEFINED_ERROR int32 = 106
|
||||||
|
TD_REQ_NONCE int32 = 107
|
||||||
|
TD_REQ_SEQ int32 = 108
|
||||||
|
TD_DH_PARAMETERS int32 = 109
|
||||||
|
//UNASSIGNED : 110
|
||||||
|
TD_CMS_DIGEST_ALGORITHMS int32 = 111
|
||||||
|
TD_CERT_DIGEST_ALGORITHMS int32 = 112
|
||||||
|
//UNASSIGNED : 113-127
|
||||||
|
PA_PAC_REQUEST int32 = 128
|
||||||
|
PA_FOR_USER int32 = 129
|
||||||
|
PA_FOR_X509_USER int32 = 130
|
||||||
|
PA_FOR_CHECK_DUPS int32 = 131
|
||||||
|
PA_AS_CHECKSUM int32 = 132
|
||||||
|
PA_FX_COOKIE int32 = 133
|
||||||
|
PA_AUTHENTICATION_SET int32 = 134
|
||||||
|
PA_AUTH_SET_SELECTED int32 = 135
|
||||||
|
PA_FX_FAST int32 = 136
|
||||||
|
PA_FX_ERROR int32 = 137
|
||||||
|
PA_ENCRYPTED_CHALLENGE int32 = 138
|
||||||
|
//UNASSIGNED : 139-140
|
||||||
|
PA_OTP_CHALLENGE int32 = 141
|
||||||
|
PA_OTP_REQUEST int32 = 142
|
||||||
|
PA_OTP_CONFIRM int32 = 143
|
||||||
|
PA_OTP_PIN_CHANGE int32 = 144
|
||||||
|
PA_EPAK_AS_REQ int32 = 145
|
||||||
|
PA_EPAK_AS_REP int32 = 146
|
||||||
|
PA_PKINIT_KX int32 = 147
|
||||||
|
PA_PKU2U_NAME int32 = 148
|
||||||
|
PA_REQ_ENC_PA_REP int32 = 149
|
||||||
|
PA_AS_FRESHNESS int32 = 150
|
||||||
|
//UNASSIGNED : 151-164
|
||||||
|
PA_SUPPORTED_ETYPES int32 = 165
|
||||||
|
PA_EXTENDED_ERROR int32 = 166
|
||||||
|
)
|
23
vendor/github.com/jcmturner/gokrb5/v8/kadmin/changepasswddata.go
generated
vendored
Normal file
23
vendor/github.com/jcmturner/gokrb5/v8/kadmin/changepasswddata.go
generated
vendored
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
package kadmin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/jcmturner/gofork/encoding/asn1"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ChangePasswdData is the payload to a password change message.
|
||||||
|
type ChangePasswdData struct {
|
||||||
|
NewPasswd []byte `asn1:"explicit,tag:0"`
|
||||||
|
TargName types.PrincipalName `asn1:"explicit,optional,tag:1"`
|
||||||
|
TargRealm string `asn1:"generalstring,optional,explicit,tag:2"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marshal ChangePasswdData into a byte slice.
|
||||||
|
func (c *ChangePasswdData) Marshal() ([]byte, error) {
|
||||||
|
b, err := asn1.Marshal(*c)
|
||||||
|
if err != nil {
|
||||||
|
return []byte{}, err
|
||||||
|
}
|
||||||
|
//b = asn1tools.AddASNAppTag(b, asnAppTag.)
|
||||||
|
return b, nil
|
||||||
|
}
|
114
vendor/github.com/jcmturner/gokrb5/v8/kadmin/message.go
generated
vendored
Normal file
114
vendor/github.com/jcmturner/gokrb5/v8/kadmin/message.go
generated
vendored
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
package kadmin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
|
||||||
|
"github.com/jcmturner/gokrb5/v8/messages"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
verisonHex = "ff80"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Request message for changing password.
|
||||||
|
type Request struct {
|
||||||
|
APREQ messages.APReq
|
||||||
|
KRBPriv messages.KRBPriv
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reply message for a password change.
|
||||||
|
type Reply struct {
|
||||||
|
MessageLength int
|
||||||
|
Version int
|
||||||
|
APREPLength int
|
||||||
|
APREP messages.APRep
|
||||||
|
KRBPriv messages.KRBPriv
|
||||||
|
KRBError messages.KRBError
|
||||||
|
IsKRBError bool
|
||||||
|
ResultCode uint16
|
||||||
|
Result string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marshal a Request into a byte slice.
|
||||||
|
func (m *Request) Marshal() (b []byte, err error) {
|
||||||
|
b = []byte{255, 128} // protocol version number: contains the hex constant 0xff80 (big-endian integer).
|
||||||
|
ab, e := m.APREQ.Marshal()
|
||||||
|
if e != nil {
|
||||||
|
err = fmt.Errorf("error marshaling AP_REQ: %v", e)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(ab) > math.MaxUint16 {
|
||||||
|
err = errors.New("length of AP_REQ greater then max Uint16 size")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
al := make([]byte, 2)
|
||||||
|
binary.BigEndian.PutUint16(al, uint16(len(ab)))
|
||||||
|
b = append(b, al...)
|
||||||
|
b = append(b, ab...)
|
||||||
|
pb, e := m.KRBPriv.Marshal()
|
||||||
|
if e != nil {
|
||||||
|
err = fmt.Errorf("error marshaling KRB_Priv: %v", e)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
b = append(b, pb...)
|
||||||
|
if len(b)+2 > math.MaxUint16 {
|
||||||
|
err = errors.New("length of message greater then max Uint16 size")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ml := make([]byte, 2)
|
||||||
|
binary.BigEndian.PutUint16(ml, uint16(len(b)+2))
|
||||||
|
b = append(ml, b...)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshal a byte slice into a Reply.
|
||||||
|
func (m *Reply) Unmarshal(b []byte) error {
|
||||||
|
m.MessageLength = int(binary.BigEndian.Uint16(b[0:2]))
|
||||||
|
m.Version = int(binary.BigEndian.Uint16(b[2:4]))
|
||||||
|
if m.Version != 1 {
|
||||||
|
return fmt.Errorf("kadmin reply has incorrect protocol version number: %d", m.Version)
|
||||||
|
}
|
||||||
|
m.APREPLength = int(binary.BigEndian.Uint16(b[4:6]))
|
||||||
|
if m.APREPLength != 0 {
|
||||||
|
err := m.APREP.Unmarshal(b[6 : 6+m.APREPLength])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = m.KRBPriv.Unmarshal(b[6+m.APREPLength : m.MessageLength])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
m.IsKRBError = true
|
||||||
|
m.KRBError.Unmarshal(b[6:m.MessageLength])
|
||||||
|
m.ResultCode, m.Result = parseResponse(m.KRBError.EData)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseResponse(b []byte) (c uint16, s string) {
|
||||||
|
c = binary.BigEndian.Uint16(b[0:2])
|
||||||
|
buf := bytes.NewBuffer(b[2:])
|
||||||
|
m := make([]byte, len(b)-2)
|
||||||
|
binary.Read(buf, binary.BigEndian, &m)
|
||||||
|
s = string(m)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decrypt the encrypted part of the KRBError within the change password Reply.
|
||||||
|
func (m *Reply) Decrypt(key types.EncryptionKey) error {
|
||||||
|
if m.IsKRBError {
|
||||||
|
return m.KRBError
|
||||||
|
}
|
||||||
|
err := m.KRBPriv.DecryptEncPart(key)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
m.ResultCode, m.Result = parseResponse(m.KRBPriv.DecryptedEncPart.UserData)
|
||||||
|
return nil
|
||||||
|
}
|
68
vendor/github.com/jcmturner/gokrb5/v8/kadmin/passwd.go
generated
vendored
Normal file
68
vendor/github.com/jcmturner/gokrb5/v8/kadmin/passwd.go
generated
vendored
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
// Package kadmin provides Kerberos administration capabilities.
|
||||||
|
package kadmin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/jcmturner/gokrb5/v8/crypto"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/krberror"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/messages"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ChangePasswdMsg generate a change password request and also return the key needed to decrypt the reply.
|
||||||
|
func ChangePasswdMsg(cname types.PrincipalName, realm, password string, tkt messages.Ticket, sessionKey types.EncryptionKey) (r Request, k types.EncryptionKey, err error) {
|
||||||
|
// Create change password data struct and marshal to bytes
|
||||||
|
chgpasswd := ChangePasswdData{
|
||||||
|
NewPasswd: []byte(password),
|
||||||
|
TargName: cname,
|
||||||
|
TargRealm: realm,
|
||||||
|
}
|
||||||
|
chpwdb, err := chgpasswd.Marshal()
|
||||||
|
if err != nil {
|
||||||
|
err = krberror.Errorf(err, krberror.KRBMsgError, "error marshaling change passwd data")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate authenticator
|
||||||
|
auth, err := types.NewAuthenticator(realm, cname)
|
||||||
|
if err != nil {
|
||||||
|
err = krberror.Errorf(err, krberror.KRBMsgError, "error generating new authenticator")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
etype, err := crypto.GetEtype(sessionKey.KeyType)
|
||||||
|
if err != nil {
|
||||||
|
err = krberror.Errorf(err, krberror.KRBMsgError, "error generating subkey etype")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = auth.GenerateSeqNumberAndSubKey(etype.GetETypeID(), etype.GetKeyByteSize())
|
||||||
|
if err != nil {
|
||||||
|
err = krberror.Errorf(err, krberror.KRBMsgError, "error generating subkey")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
k = auth.SubKey
|
||||||
|
|
||||||
|
// Generate AP_REQ
|
||||||
|
APreq, err := messages.NewAPReq(tkt, sessionKey, auth)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Form the KRBPriv encpart data
|
||||||
|
kp := messages.EncKrbPrivPart{
|
||||||
|
UserData: chpwdb,
|
||||||
|
Timestamp: auth.CTime,
|
||||||
|
Usec: auth.Cusec,
|
||||||
|
SequenceNumber: auth.SeqNumber,
|
||||||
|
}
|
||||||
|
kpriv := messages.NewKRBPriv(kp)
|
||||||
|
err = kpriv.EncryptEncPart(k)
|
||||||
|
if err != nil {
|
||||||
|
err = krberror.Errorf(err, krberror.EncryptingError, "error encrypting change passwd data")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
r = Request{
|
||||||
|
APREQ: APreq,
|
||||||
|
KRBPriv: kpriv,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
470
vendor/github.com/jcmturner/gokrb5/v8/keytab/keytab.go
generated
vendored
Normal file
470
vendor/github.com/jcmturner/gokrb5/v8/keytab/keytab.go
generated
vendored
Normal file
|
@ -0,0 +1,470 @@
|
||||||
|
// Package keytab implements Kerberos keytabs: https://web.mit.edu/kerberos/krb5-devel/doc/formats/keytab_file_format.html.
|
||||||
|
package keytab
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"time"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/jcmturner/gokrb5/v8/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
keytabFirstByte byte = 05
|
||||||
|
)
|
||||||
|
|
||||||
|
// Keytab struct.
|
||||||
|
type Keytab struct {
|
||||||
|
version uint8
|
||||||
|
Entries []entry
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keytab entry struct.
|
||||||
|
type entry struct {
|
||||||
|
Principal principal
|
||||||
|
Timestamp time.Time
|
||||||
|
KVNO8 uint8
|
||||||
|
Key types.EncryptionKey
|
||||||
|
KVNO uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keytab entry principal struct.
|
||||||
|
type principal struct {
|
||||||
|
NumComponents int16 `json:"-"`
|
||||||
|
Realm string
|
||||||
|
Components []string
|
||||||
|
NameType int32
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates new, empty Keytab type.
|
||||||
|
func New() *Keytab {
|
||||||
|
var e []entry
|
||||||
|
return &Keytab{
|
||||||
|
version: 0,
|
||||||
|
Entries: e,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetEncryptionKey returns the EncryptionKey from the Keytab for the newest entry with the required kvno, etype and matching principal.
|
||||||
|
// If the kvno is zero then the latest kvno will be returned. The kvno is also returned for
|
||||||
|
func (kt *Keytab) GetEncryptionKey(princName types.PrincipalName, realm string, kvno int, etype int32) (types.EncryptionKey, int, error) {
|
||||||
|
var key types.EncryptionKey
|
||||||
|
var t time.Time
|
||||||
|
for _, k := range kt.Entries {
|
||||||
|
if k.Principal.Realm == realm && len(k.Principal.Components) == len(princName.NameString) &&
|
||||||
|
k.Key.KeyType == etype &&
|
||||||
|
(k.KVNO == uint32(kvno) || kvno == 0) &&
|
||||||
|
k.Timestamp.After(t) {
|
||||||
|
p := true
|
||||||
|
for i, n := range k.Principal.Components {
|
||||||
|
if princName.NameString[i] != n {
|
||||||
|
p = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if p {
|
||||||
|
key = k.Key
|
||||||
|
kvno = int(k.KVNO)
|
||||||
|
t = k.Timestamp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(key.KeyValue) < 1 {
|
||||||
|
return key, 0, fmt.Errorf("matching key not found in keytab. Looking for %v realm: %v kvno: %v etype: %v", princName.NameString, realm, kvno, etype)
|
||||||
|
}
|
||||||
|
return key, kvno, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new Keytab entry.
|
||||||
|
func newEntry() entry {
|
||||||
|
var b []byte
|
||||||
|
return entry{
|
||||||
|
Principal: newPrincipal(),
|
||||||
|
Timestamp: time.Time{},
|
||||||
|
KVNO8: 0,
|
||||||
|
Key: types.EncryptionKey{
|
||||||
|
KeyType: 0,
|
||||||
|
KeyValue: b,
|
||||||
|
},
|
||||||
|
KVNO: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new principal.
|
||||||
|
func newPrincipal() principal {
|
||||||
|
var c []string
|
||||||
|
return principal{
|
||||||
|
NumComponents: 0,
|
||||||
|
Realm: "",
|
||||||
|
Components: c,
|
||||||
|
NameType: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load a Keytab file into a Keytab type.
|
||||||
|
func Load(ktPath string) (*Keytab, error) {
|
||||||
|
kt := new(Keytab)
|
||||||
|
b, err := ioutil.ReadFile(ktPath)
|
||||||
|
if err != nil {
|
||||||
|
return kt, err
|
||||||
|
}
|
||||||
|
err = kt.Unmarshal(b)
|
||||||
|
return kt, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marshal keytab into byte slice
|
||||||
|
func (kt *Keytab) Marshal() ([]byte, error) {
|
||||||
|
b := []byte{keytabFirstByte, kt.version}
|
||||||
|
for _, e := range kt.Entries {
|
||||||
|
eb, err := e.marshal(int(kt.version))
|
||||||
|
if err != nil {
|
||||||
|
return b, err
|
||||||
|
}
|
||||||
|
b = append(b, eb...)
|
||||||
|
}
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the keytab bytes to io.Writer.
|
||||||
|
// Returns the number of bytes written
|
||||||
|
func (kt *Keytab) Write(w io.Writer) (int, error) {
|
||||||
|
b, err := kt.Marshal()
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("error marshaling keytab: %v", err)
|
||||||
|
}
|
||||||
|
return w.Write(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshal byte slice of Keytab data into Keytab type.
|
||||||
|
func (kt *Keytab) Unmarshal(b []byte) error {
|
||||||
|
if len(b) < 2 {
|
||||||
|
return fmt.Errorf("byte array is less than 2 bytes: %d", len(b))
|
||||||
|
}
|
||||||
|
|
||||||
|
//The first byte of the file always has the value 5
|
||||||
|
if b[0] != keytabFirstByte {
|
||||||
|
return errors.New("invalid keytab data. First byte does not equal 5")
|
||||||
|
}
|
||||||
|
//Get keytab version
|
||||||
|
//The 2nd byte contains the version number (1 or 2)
|
||||||
|
kt.version = b[1]
|
||||||
|
if kt.version != 1 && kt.version != 2 {
|
||||||
|
return errors.New("invalid keytab data. Keytab version is neither 1 nor 2")
|
||||||
|
}
|
||||||
|
//Version 1 of the file format uses native byte order for integer representations. Version 2 always uses big-endian byte order
|
||||||
|
var endian binary.ByteOrder
|
||||||
|
endian = binary.BigEndian
|
||||||
|
if kt.version == 1 && isNativeEndianLittle() {
|
||||||
|
endian = binary.LittleEndian
|
||||||
|
}
|
||||||
|
// n tracks position in the byte array
|
||||||
|
n := 2
|
||||||
|
l, err := readInt32(b, &n, &endian)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for l != 0 {
|
||||||
|
if l < 0 {
|
||||||
|
//Zero padded so skip over
|
||||||
|
l = l * -1
|
||||||
|
n = n + int(l)
|
||||||
|
} else {
|
||||||
|
if n < 0 {
|
||||||
|
return fmt.Errorf("%d can't be less than zero", n)
|
||||||
|
}
|
||||||
|
if n+int(l) > len(b) {
|
||||||
|
return fmt.Errorf("%s's length is less than %d", b, n+int(l))
|
||||||
|
}
|
||||||
|
eb := b[n : n+int(l)]
|
||||||
|
n = n + int(l)
|
||||||
|
ke := newEntry()
|
||||||
|
// p keeps track as to where we are in the byte stream
|
||||||
|
var p int
|
||||||
|
var err error
|
||||||
|
parsePrincipal(eb, &p, kt, &ke, &endian)
|
||||||
|
ke.Timestamp, err = readTimestamp(eb, &p, &endian)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
rei8, err := readInt8(eb, &p, &endian)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ke.KVNO8 = uint8(rei8)
|
||||||
|
rei16, err := readInt16(eb, &p, &endian)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ke.Key.KeyType = int32(rei16)
|
||||||
|
rei16, err = readInt16(eb, &p, &endian)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
kl := int(rei16)
|
||||||
|
ke.Key.KeyValue, err = readBytes(eb, &p, kl, &endian)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// The 32-bit key version overrides the 8-bit key version.
|
||||||
|
// If at least 4 bytes are left after the other fields are read and they are non-zero
|
||||||
|
// this indicates the 32-bit version is present.
|
||||||
|
if len(eb)-p >= 4 {
|
||||||
|
// The 32-bit key may be present
|
||||||
|
ri32, err := readInt32(eb, &p, &endian)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ke.KVNO = uint32(ri32)
|
||||||
|
}
|
||||||
|
if ke.KVNO == 0 {
|
||||||
|
// Handles if the value from the last 4 bytes was zero and also if there are not the 4 bytes present. Makes sense to put the same value here as KVNO8
|
||||||
|
ke.KVNO = uint32(ke.KVNO8)
|
||||||
|
}
|
||||||
|
// Add the entry to the keytab
|
||||||
|
kt.Entries = append(kt.Entries, ke)
|
||||||
|
}
|
||||||
|
// Check if there are still 4 bytes left to read
|
||||||
|
// Also check that n is greater than zero
|
||||||
|
if n < 0 || n > len(b) || len(b[n:]) < 4 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// Read the size of the next entry
|
||||||
|
l, err = readInt32(b, &n, &endian)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e entry) marshal(v int) ([]byte, error) {
|
||||||
|
var b []byte
|
||||||
|
pb, err := e.Principal.marshal(v)
|
||||||
|
if err != nil {
|
||||||
|
return b, err
|
||||||
|
}
|
||||||
|
b = append(b, pb...)
|
||||||
|
|
||||||
|
var endian binary.ByteOrder
|
||||||
|
endian = binary.BigEndian
|
||||||
|
if v == 1 && isNativeEndianLittle() {
|
||||||
|
endian = binary.LittleEndian
|
||||||
|
}
|
||||||
|
|
||||||
|
t := make([]byte, 9)
|
||||||
|
endian.PutUint32(t[0:4], uint32(e.Timestamp.Unix()))
|
||||||
|
t[4] = e.KVNO8
|
||||||
|
endian.PutUint16(t[5:7], uint16(e.Key.KeyType))
|
||||||
|
endian.PutUint16(t[7:9], uint16(len(e.Key.KeyValue)))
|
||||||
|
b = append(b, t...)
|
||||||
|
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
err = binary.Write(buf, endian, e.Key.KeyValue)
|
||||||
|
if err != nil {
|
||||||
|
return b, err
|
||||||
|
}
|
||||||
|
b = append(b, buf.Bytes()...)
|
||||||
|
|
||||||
|
t = make([]byte, 4)
|
||||||
|
endian.PutUint32(t, e.KVNO)
|
||||||
|
b = append(b, t...)
|
||||||
|
|
||||||
|
// Add the length header
|
||||||
|
t = make([]byte, 4)
|
||||||
|
endian.PutUint32(t, uint32(len(b)))
|
||||||
|
b = append(t, b...)
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the Keytab bytes of a principal into a Keytab entry's principal.
|
||||||
|
func parsePrincipal(b []byte, p *int, kt *Keytab, ke *entry, e *binary.ByteOrder) error {
|
||||||
|
var err error
|
||||||
|
ke.Principal.NumComponents, err = readInt16(b, p, e)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if kt.version == 1 {
|
||||||
|
//In version 1 the number of components includes the realm. Minus 1 to make consistent with version 2
|
||||||
|
ke.Principal.NumComponents--
|
||||||
|
}
|
||||||
|
lenRealm, err := readInt16(b, p, e)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
realmB, err := readBytes(b, p, int(lenRealm), e)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ke.Principal.Realm = string(realmB)
|
||||||
|
for i := 0; i < int(ke.Principal.NumComponents); i++ {
|
||||||
|
l, err := readInt16(b, p, e)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
compB, err := readBytes(b, p, int(l), e)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ke.Principal.Components = append(ke.Principal.Components, string(compB))
|
||||||
|
}
|
||||||
|
if kt.version != 1 {
|
||||||
|
//Name Type is omitted in version 1
|
||||||
|
ke.Principal.NameType, err = readInt32(b, p, e)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p principal) marshal(v int) ([]byte, error) {
|
||||||
|
//var b []byte
|
||||||
|
b := make([]byte, 2)
|
||||||
|
var endian binary.ByteOrder
|
||||||
|
endian = binary.BigEndian
|
||||||
|
if v == 1 && isNativeEndianLittle() {
|
||||||
|
endian = binary.LittleEndian
|
||||||
|
}
|
||||||
|
endian.PutUint16(b[0:], uint16(p.NumComponents))
|
||||||
|
realm, err := marshalString(p.Realm, v)
|
||||||
|
if err != nil {
|
||||||
|
return b, err
|
||||||
|
}
|
||||||
|
b = append(b, realm...)
|
||||||
|
for _, c := range p.Components {
|
||||||
|
cb, err := marshalString(c, v)
|
||||||
|
if err != nil {
|
||||||
|
return b, err
|
||||||
|
}
|
||||||
|
b = append(b, cb...)
|
||||||
|
}
|
||||||
|
if v != 1 {
|
||||||
|
t := make([]byte, 4)
|
||||||
|
endian.PutUint32(t, uint32(p.NameType))
|
||||||
|
b = append(b, t...)
|
||||||
|
}
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshalString(s string, v int) ([]byte, error) {
|
||||||
|
sb := []byte(s)
|
||||||
|
b := make([]byte, 2)
|
||||||
|
var endian binary.ByteOrder
|
||||||
|
endian = binary.BigEndian
|
||||||
|
if v == 1 && isNativeEndianLittle() {
|
||||||
|
endian = binary.LittleEndian
|
||||||
|
}
|
||||||
|
endian.PutUint16(b[0:], uint16(len(sb)))
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
err := binary.Write(buf, endian, sb)
|
||||||
|
if err != nil {
|
||||||
|
return b, err
|
||||||
|
}
|
||||||
|
b = append(b, buf.Bytes()...)
|
||||||
|
return b, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read bytes representing a timestamp.
|
||||||
|
func readTimestamp(b []byte, p *int, e *binary.ByteOrder) (time.Time, error) {
|
||||||
|
i32, err := readInt32(b, p, e)
|
||||||
|
if err != nil {
|
||||||
|
return time.Time{}, err
|
||||||
|
}
|
||||||
|
return time.Unix(int64(i32), 0), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read bytes representing an eight bit integer.
|
||||||
|
func readInt8(b []byte, p *int, e *binary.ByteOrder) (i int8, err error) {
|
||||||
|
if *p < 0 {
|
||||||
|
return 0, fmt.Errorf("%d cannot be less than zero", *p)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*p + 1) > len(b) {
|
||||||
|
return 0, fmt.Errorf("%s's length is less than %d", b, *p+1)
|
||||||
|
}
|
||||||
|
buf := bytes.NewBuffer(b[*p : *p+1])
|
||||||
|
binary.Read(buf, *e, &i)
|
||||||
|
*p++
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read bytes representing a sixteen bit integer.
|
||||||
|
func readInt16(b []byte, p *int, e *binary.ByteOrder) (i int16, err error) {
|
||||||
|
if *p < 0 {
|
||||||
|
return 0, fmt.Errorf("%d cannot be less than zero", *p)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*p + 2) > len(b) {
|
||||||
|
return 0, fmt.Errorf("%s's length is less than %d", b, *p+2)
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := bytes.NewBuffer(b[*p : *p+2])
|
||||||
|
binary.Read(buf, *e, &i)
|
||||||
|
*p += 2
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read bytes representing a thirty two bit integer.
|
||||||
|
func readInt32(b []byte, p *int, e *binary.ByteOrder) (i int32, err error) {
|
||||||
|
if *p < 0 {
|
||||||
|
return 0, fmt.Errorf("%d cannot be less than zero", *p)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*p + 4) > len(b) {
|
||||||
|
return 0, fmt.Errorf("%s's length is less than %d", b, *p+4)
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := bytes.NewBuffer(b[*p : *p+4])
|
||||||
|
binary.Read(buf, *e, &i)
|
||||||
|
*p += 4
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func readBytes(b []byte, p *int, s int, e *binary.ByteOrder) ([]byte, error) {
|
||||||
|
if s < 0 {
|
||||||
|
return nil, fmt.Errorf("%d cannot be less than zero", s)
|
||||||
|
}
|
||||||
|
i := *p + s
|
||||||
|
if i > len(b) {
|
||||||
|
return nil, fmt.Errorf("%s's length is greater than %d", b, i)
|
||||||
|
}
|
||||||
|
buf := bytes.NewBuffer(b[*p:i])
|
||||||
|
r := make([]byte, s)
|
||||||
|
if err := binary.Read(buf, *e, &r); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
*p += s
|
||||||
|
return r, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isNativeEndianLittle() bool {
|
||||||
|
var x = 0x012345678
|
||||||
|
var p = unsafe.Pointer(&x)
|
||||||
|
var bp = (*[4]byte)(p)
|
||||||
|
|
||||||
|
var endian bool
|
||||||
|
if 0x01 == bp[0] {
|
||||||
|
endian = false
|
||||||
|
} else if (0x78 & 0xff) == (bp[0] & 0xff) {
|
||||||
|
endian = true
|
||||||
|
} else {
|
||||||
|
// Default to big endian
|
||||||
|
endian = false
|
||||||
|
}
|
||||||
|
return endian
|
||||||
|
}
|
||||||
|
|
||||||
|
// JSON return information about the keys held in the keytab in a JSON format.
|
||||||
|
func (k *Keytab) JSON() (string, error) {
|
||||||
|
b, err := json.MarshalIndent(k, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(b), nil
|
||||||
|
}
|
67
vendor/github.com/jcmturner/gokrb5/v8/krberror/error.go
generated
vendored
Normal file
67
vendor/github.com/jcmturner/gokrb5/v8/krberror/error.go
generated
vendored
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
// Package krberror provides error type and functions for gokrb5.
|
||||||
|
package krberror
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Error type descriptions.
|
||||||
|
const (
|
||||||
|
separator = " < "
|
||||||
|
EncodingError = "Encoding_Error"
|
||||||
|
NetworkingError = "Networking_Error"
|
||||||
|
DecryptingError = "Decrypting_Error"
|
||||||
|
EncryptingError = "Encrypting_Error"
|
||||||
|
ChksumError = "Checksum_Error"
|
||||||
|
KRBMsgError = "KRBMessage_Handling_Error"
|
||||||
|
ConfigError = "Configuration_Error"
|
||||||
|
KDCError = "KDC_Error"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Krberror is an error type for gokrb5
|
||||||
|
type Krberror struct {
|
||||||
|
RootCause string
|
||||||
|
EText []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error function to implement the error interface.
|
||||||
|
func (e Krberror) Error() string {
|
||||||
|
return fmt.Sprintf("[Root cause: %s] ", e.RootCause) + strings.Join(e.EText, separator)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add another error statement to the error.
|
||||||
|
func (e *Krberror) Add(et string, s string) {
|
||||||
|
e.EText = append([]string{fmt.Sprintf("%s: %s", et, s)}, e.EText...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates a new instance of Krberror.
|
||||||
|
func New(et, s string) Krberror {
|
||||||
|
return Krberror{
|
||||||
|
RootCause: et,
|
||||||
|
EText: []string{s},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Errorf appends to or creates a new Krberror.
|
||||||
|
func Errorf(err error, et, format string, a ...interface{}) Krberror {
|
||||||
|
if e, ok := err.(Krberror); ok {
|
||||||
|
e.Add(et, fmt.Sprintf(format, a...))
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
return NewErrorf(et, format+": %s", append(a, err)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewErrorf creates a new Krberror from a formatted string.
|
||||||
|
func NewErrorf(et, format string, a ...interface{}) Krberror {
|
||||||
|
var s string
|
||||||
|
if len(a) > 0 {
|
||||||
|
s = fmt.Sprintf("%s: %s", et, fmt.Sprintf(format, a...))
|
||||||
|
} else {
|
||||||
|
s = fmt.Sprintf("%s: %s", et, format)
|
||||||
|
}
|
||||||
|
return Krberror{
|
||||||
|
RootCause: et,
|
||||||
|
EText: []string{s},
|
||||||
|
}
|
||||||
|
}
|
49
vendor/github.com/jcmturner/gokrb5/v8/messages/APRep.go
generated
vendored
Normal file
49
vendor/github.com/jcmturner/gokrb5/v8/messages/APRep.go
generated
vendored
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
package messages
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/jcmturner/gofork/encoding/asn1"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/asnAppTag"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/msgtype"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/krberror"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// APRep implements RFC 4120 KRB_AP_REP: https://tools.ietf.org/html/rfc4120#section-5.5.2.
|
||||||
|
type APRep struct {
|
||||||
|
PVNO int `asn1:"explicit,tag:0"`
|
||||||
|
MsgType int `asn1:"explicit,tag:1"`
|
||||||
|
EncPart types.EncryptedData `asn1:"explicit,tag:2"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncAPRepPart is the encrypted part of KRB_AP_REP.
|
||||||
|
type EncAPRepPart struct {
|
||||||
|
CTime time.Time `asn1:"generalized,explicit,tag:0"`
|
||||||
|
Cusec int `asn1:"explicit,tag:1"`
|
||||||
|
Subkey types.EncryptionKey `asn1:"optional,explicit,tag:2"`
|
||||||
|
SequenceNumber int64 `asn1:"optional,explicit,tag:3"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshal bytes b into the APRep struct.
|
||||||
|
func (a *APRep) Unmarshal(b []byte) error {
|
||||||
|
_, err := asn1.UnmarshalWithParams(b, a, fmt.Sprintf("application,explicit,tag:%v", asnAppTag.APREP))
|
||||||
|
if err != nil {
|
||||||
|
return processUnmarshalReplyError(b, err)
|
||||||
|
}
|
||||||
|
expectedMsgType := msgtype.KRB_AP_REP
|
||||||
|
if a.MsgType != expectedMsgType {
|
||||||
|
return krberror.NewErrorf(krberror.KRBMsgError, "message ID does not indicate a KRB_AP_REP. Expected: %v; Actual: %v", expectedMsgType, a.MsgType)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshal bytes b into the APRep encrypted part struct.
|
||||||
|
func (a *EncAPRepPart) Unmarshal(b []byte) error {
|
||||||
|
_, err := asn1.UnmarshalWithParams(b, a, fmt.Sprintf("application,explicit,tag:%v", asnAppTag.EncAPRepPart))
|
||||||
|
if err != nil {
|
||||||
|
return krberror.Errorf(err, krberror.EncodingError, "AP_REP unmarshal error")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
199
vendor/github.com/jcmturner/gokrb5/v8/messages/APReq.go
generated
vendored
Normal file
199
vendor/github.com/jcmturner/gokrb5/v8/messages/APReq.go
generated
vendored
Normal file
|
@ -0,0 +1,199 @@
|
||||||
|
package messages
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/jcmturner/gofork/encoding/asn1"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/asn1tools"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/crypto"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/asnAppTag"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/errorcode"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/keyusage"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/msgtype"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/keytab"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/krberror"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
type marshalAPReq struct {
|
||||||
|
PVNO int `asn1:"explicit,tag:0"`
|
||||||
|
MsgType int `asn1:"explicit,tag:1"`
|
||||||
|
APOptions asn1.BitString `asn1:"explicit,tag:2"`
|
||||||
|
// Ticket needs to be a raw value as it is wrapped in an APPLICATION tag
|
||||||
|
Ticket asn1.RawValue `asn1:"explicit,tag:3"`
|
||||||
|
EncryptedAuthenticator types.EncryptedData `asn1:"explicit,tag:4"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// APReq implements RFC 4120 KRB_AP_REQ: https://tools.ietf.org/html/rfc4120#section-5.5.1.
|
||||||
|
type APReq struct {
|
||||||
|
PVNO int `asn1:"explicit,tag:0"`
|
||||||
|
MsgType int `asn1:"explicit,tag:1"`
|
||||||
|
APOptions asn1.BitString `asn1:"explicit,tag:2"`
|
||||||
|
Ticket Ticket `asn1:"explicit,tag:3"`
|
||||||
|
EncryptedAuthenticator types.EncryptedData `asn1:"explicit,tag:4"`
|
||||||
|
Authenticator types.Authenticator `asn1:"optional"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAPReq generates a new KRB_AP_REQ struct.
|
||||||
|
func NewAPReq(tkt Ticket, sessionKey types.EncryptionKey, auth types.Authenticator) (APReq, error) {
|
||||||
|
var a APReq
|
||||||
|
ed, err := encryptAuthenticator(auth, sessionKey, tkt)
|
||||||
|
if err != nil {
|
||||||
|
return a, krberror.Errorf(err, krberror.KRBMsgError, "error creating Authenticator for AP_REQ")
|
||||||
|
}
|
||||||
|
a = APReq{
|
||||||
|
PVNO: iana.PVNO,
|
||||||
|
MsgType: msgtype.KRB_AP_REQ,
|
||||||
|
APOptions: types.NewKrbFlags(),
|
||||||
|
Ticket: tkt,
|
||||||
|
EncryptedAuthenticator: ed,
|
||||||
|
}
|
||||||
|
return a, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encrypt Authenticator
|
||||||
|
func encryptAuthenticator(a types.Authenticator, sessionKey types.EncryptionKey, tkt Ticket) (types.EncryptedData, error) {
|
||||||
|
var ed types.EncryptedData
|
||||||
|
m, err := a.Marshal()
|
||||||
|
if err != nil {
|
||||||
|
return ed, krberror.Errorf(err, krberror.EncodingError, "marshaling error of EncryptedData form of Authenticator")
|
||||||
|
}
|
||||||
|
usage := authenticatorKeyUsage(tkt.SName)
|
||||||
|
ed, err = crypto.GetEncryptedData(m, sessionKey, uint32(usage), tkt.EncPart.KVNO)
|
||||||
|
if err != nil {
|
||||||
|
return ed, krberror.Errorf(err, krberror.EncryptingError, "error encrypting Authenticator")
|
||||||
|
}
|
||||||
|
return ed, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecryptAuthenticator decrypts the Authenticator within the AP_REQ.
|
||||||
|
// sessionKey may simply be the key within the decrypted EncPart of the ticket within the AP_REQ.
|
||||||
|
func (a *APReq) DecryptAuthenticator(sessionKey types.EncryptionKey) error {
|
||||||
|
usage := authenticatorKeyUsage(a.Ticket.SName)
|
||||||
|
ab, e := crypto.DecryptEncPart(a.EncryptedAuthenticator, sessionKey, uint32(usage))
|
||||||
|
if e != nil {
|
||||||
|
return fmt.Errorf("error decrypting authenticator: %v", e)
|
||||||
|
}
|
||||||
|
err := a.Authenticator.Unmarshal(ab)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error unmarshaling authenticator: %v", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func authenticatorKeyUsage(pn types.PrincipalName) int {
|
||||||
|
if pn.NameString[0] == "krbtgt" {
|
||||||
|
return keyusage.TGS_REQ_PA_TGS_REQ_AP_REQ_AUTHENTICATOR
|
||||||
|
}
|
||||||
|
return keyusage.AP_REQ_AUTHENTICATOR
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshal bytes b into the APReq struct.
|
||||||
|
func (a *APReq) Unmarshal(b []byte) error {
|
||||||
|
var m marshalAPReq
|
||||||
|
_, err := asn1.UnmarshalWithParams(b, &m, fmt.Sprintf("application,explicit,tag:%v", asnAppTag.APREQ))
|
||||||
|
if err != nil {
|
||||||
|
return krberror.Errorf(err, krberror.EncodingError, "unmarshal error of AP_REQ")
|
||||||
|
}
|
||||||
|
if m.MsgType != msgtype.KRB_AP_REQ {
|
||||||
|
return NewKRBError(types.PrincipalName{}, "", errorcode.KRB_AP_ERR_MSG_TYPE, errorcode.Lookup(errorcode.KRB_AP_ERR_MSG_TYPE))
|
||||||
|
}
|
||||||
|
a.PVNO = m.PVNO
|
||||||
|
a.MsgType = m.MsgType
|
||||||
|
a.APOptions = m.APOptions
|
||||||
|
a.EncryptedAuthenticator = m.EncryptedAuthenticator
|
||||||
|
a.Ticket, err = unmarshalTicket(m.Ticket.Bytes)
|
||||||
|
if err != nil {
|
||||||
|
return krberror.Errorf(err, krberror.EncodingError, "unmarshaling error of Ticket within AP_REQ")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marshal APReq struct.
|
||||||
|
func (a *APReq) Marshal() ([]byte, error) {
|
||||||
|
m := marshalAPReq{
|
||||||
|
PVNO: a.PVNO,
|
||||||
|
MsgType: a.MsgType,
|
||||||
|
APOptions: a.APOptions,
|
||||||
|
EncryptedAuthenticator: a.EncryptedAuthenticator,
|
||||||
|
}
|
||||||
|
var b []byte
|
||||||
|
b, err := a.Ticket.Marshal()
|
||||||
|
if err != nil {
|
||||||
|
return b, err
|
||||||
|
}
|
||||||
|
m.Ticket = asn1.RawValue{
|
||||||
|
Class: asn1.ClassContextSpecific,
|
||||||
|
IsCompound: true,
|
||||||
|
Tag: 3,
|
||||||
|
Bytes: b,
|
||||||
|
}
|
||||||
|
mk, err := asn1.Marshal(m)
|
||||||
|
if err != nil {
|
||||||
|
return mk, krberror.Errorf(err, krberror.EncodingError, "marshaling error of AP_REQ")
|
||||||
|
}
|
||||||
|
mk = asn1tools.AddASNAppTag(mk, asnAppTag.APREQ)
|
||||||
|
return mk, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify an AP_REQ using service's keytab, spn and max acceptable clock skew duration.
|
||||||
|
// The service ticket encrypted part and authenticator will be decrypted as part of this operation.
|
||||||
|
func (a *APReq) Verify(kt *keytab.Keytab, d time.Duration, cAddr types.HostAddress, snameOverride *types.PrincipalName) (bool, error) {
|
||||||
|
// Decrypt ticket's encrypted part with service key
|
||||||
|
//TODO decrypt with service's session key from its TGT is use-to-user. Need to figure out how to get TGT.
|
||||||
|
//if types.IsFlagSet(&a.APOptions, flags.APOptionUseSessionKey) {
|
||||||
|
// err := a.Ticket.Decrypt(tgt.DecryptedEncPart.Key)
|
||||||
|
// if err != nil {
|
||||||
|
// return false, krberror.Errorf(err, krberror.DecryptingError, "error decrypting encpart of ticket provided using session key")
|
||||||
|
// }
|
||||||
|
//} else {
|
||||||
|
// err := a.Ticket.DecryptEncPart(*kt, &a.Ticket.SName)
|
||||||
|
// if err != nil {
|
||||||
|
// return false, krberror.Errorf(err, krberror.DecryptingError, "error decrypting encpart of service ticket provided")
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
sname := &a.Ticket.SName
|
||||||
|
if snameOverride != nil {
|
||||||
|
sname = snameOverride
|
||||||
|
}
|
||||||
|
err := a.Ticket.DecryptEncPart(kt, sname)
|
||||||
|
if err != nil {
|
||||||
|
return false, krberror.Errorf(err, krberror.DecryptingError, "error decrypting encpart of service ticket provided")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check time validity of ticket
|
||||||
|
ok, err := a.Ticket.Valid(d)
|
||||||
|
if err != nil || !ok {
|
||||||
|
return ok, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check client's address is listed in the client addresses in the ticket
|
||||||
|
if len(a.Ticket.DecryptedEncPart.CAddr) > 0 {
|
||||||
|
//If client addresses are present check if any of them match the source IP that sent the APReq
|
||||||
|
//If there is no match return KRB_AP_ERR_BADADDR error.
|
||||||
|
if !types.HostAddressesContains(a.Ticket.DecryptedEncPart.CAddr, cAddr) {
|
||||||
|
return false, NewKRBError(a.Ticket.SName, a.Ticket.Realm, errorcode.KRB_AP_ERR_BADADDR, "client address not within the list contained in the service ticket")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decrypt authenticator with session key from ticket's encrypted part
|
||||||
|
err = a.DecryptAuthenticator(a.Ticket.DecryptedEncPart.Key)
|
||||||
|
if err != nil {
|
||||||
|
return false, NewKRBError(a.Ticket.SName, a.Ticket.Realm, errorcode.KRB_AP_ERR_BAD_INTEGRITY, "could not decrypt authenticator")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check CName in authenticator is the same as that in the ticket
|
||||||
|
if !a.Authenticator.CName.Equal(a.Ticket.DecryptedEncPart.CName) {
|
||||||
|
return false, NewKRBError(a.Ticket.SName, a.Ticket.Realm, errorcode.KRB_AP_ERR_BADMATCH, "CName in Authenticator does not match that in service ticket")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the clock skew between the client and the service server
|
||||||
|
ct := a.Authenticator.CTime.Add(time.Duration(a.Authenticator.Cusec) * time.Microsecond)
|
||||||
|
t := time.Now().UTC()
|
||||||
|
if t.Sub(ct) > d || ct.Sub(t) > d {
|
||||||
|
return false, NewKRBError(a.Ticket.SName, a.Ticket.Realm, errorcode.KRB_AP_ERR_SKEW, fmt.Sprintf("clock skew with client too large. greater than %v seconds", d))
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
308
vendor/github.com/jcmturner/gokrb5/v8/messages/KDCRep.go
generated
vendored
Normal file
308
vendor/github.com/jcmturner/gokrb5/v8/messages/KDCRep.go
generated
vendored
Normal file
|
@ -0,0 +1,308 @@
|
||||||
|
package messages
|
||||||
|
|
||||||
|
// Reference: https://www.ietf.org/rfc/rfc4120.txt
|
||||||
|
// Section: 5.4.2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/jcmturner/gofork/encoding/asn1"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/config"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/credentials"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/crypto"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/asnAppTag"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/flags"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/keyusage"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/msgtype"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/patype"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/krberror"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
type marshalKDCRep struct {
|
||||||
|
PVNO int `asn1:"explicit,tag:0"`
|
||||||
|
MsgType int `asn1:"explicit,tag:1"`
|
||||||
|
PAData types.PADataSequence `asn1:"explicit,optional,tag:2"`
|
||||||
|
CRealm string `asn1:"generalstring,explicit,tag:3"`
|
||||||
|
CName types.PrincipalName `asn1:"explicit,tag:4"`
|
||||||
|
// Ticket needs to be a raw value as it is wrapped in an APPLICATION tag
|
||||||
|
Ticket asn1.RawValue `asn1:"explicit,tag:5"`
|
||||||
|
EncPart types.EncryptedData `asn1:"explicit,tag:6"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// KDCRepFields represents the KRB_KDC_REP fields.
|
||||||
|
type KDCRepFields struct {
|
||||||
|
PVNO int
|
||||||
|
MsgType int
|
||||||
|
PAData []types.PAData
|
||||||
|
CRealm string
|
||||||
|
CName types.PrincipalName
|
||||||
|
Ticket Ticket
|
||||||
|
EncPart types.EncryptedData
|
||||||
|
DecryptedEncPart EncKDCRepPart
|
||||||
|
}
|
||||||
|
|
||||||
|
// ASRep implements RFC 4120 KRB_AS_REP: https://tools.ietf.org/html/rfc4120#section-5.4.2.
|
||||||
|
type ASRep struct {
|
||||||
|
KDCRepFields
|
||||||
|
}
|
||||||
|
|
||||||
|
// TGSRep implements RFC 4120 KRB_TGS_REP: https://tools.ietf.org/html/rfc4120#section-5.4.2.
|
||||||
|
type TGSRep struct {
|
||||||
|
KDCRepFields
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncKDCRepPart is the encrypted part of KRB_KDC_REP.
|
||||||
|
type EncKDCRepPart struct {
|
||||||
|
Key types.EncryptionKey `asn1:"explicit,tag:0"`
|
||||||
|
LastReqs []LastReq `asn1:"explicit,tag:1"`
|
||||||
|
Nonce int `asn1:"explicit,tag:2"`
|
||||||
|
KeyExpiration time.Time `asn1:"generalized,explicit,optional,tag:3"`
|
||||||
|
Flags asn1.BitString `asn1:"explicit,tag:4"`
|
||||||
|
AuthTime time.Time `asn1:"generalized,explicit,tag:5"`
|
||||||
|
StartTime time.Time `asn1:"generalized,explicit,optional,tag:6"`
|
||||||
|
EndTime time.Time `asn1:"generalized,explicit,tag:7"`
|
||||||
|
RenewTill time.Time `asn1:"generalized,explicit,optional,tag:8"`
|
||||||
|
SRealm string `asn1:"generalstring,explicit,tag:9"`
|
||||||
|
SName types.PrincipalName `asn1:"explicit,tag:10"`
|
||||||
|
CAddr []types.HostAddress `asn1:"explicit,optional,tag:11"`
|
||||||
|
EncPAData types.PADataSequence `asn1:"explicit,optional,tag:12"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// LastReq part of KRB_KDC_REP.
|
||||||
|
type LastReq struct {
|
||||||
|
LRType int32 `asn1:"explicit,tag:0"`
|
||||||
|
LRValue time.Time `asn1:"generalized,explicit,tag:1"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshal bytes b into the ASRep struct.
|
||||||
|
func (k *ASRep) Unmarshal(b []byte) error {
|
||||||
|
var m marshalKDCRep
|
||||||
|
_, err := asn1.UnmarshalWithParams(b, &m, fmt.Sprintf("application,explicit,tag:%v", asnAppTag.ASREP))
|
||||||
|
if err != nil {
|
||||||
|
return processUnmarshalReplyError(b, err)
|
||||||
|
}
|
||||||
|
if m.MsgType != msgtype.KRB_AS_REP {
|
||||||
|
return krberror.NewErrorf(krberror.KRBMsgError, "message ID does not indicate an AS_REP. Expected: %v; Actual: %v", msgtype.KRB_AS_REP, m.MsgType)
|
||||||
|
}
|
||||||
|
//Process the raw ticket within
|
||||||
|
tkt, err := unmarshalTicket(m.Ticket.Bytes)
|
||||||
|
if err != nil {
|
||||||
|
return krberror.Errorf(err, krberror.EncodingError, "error unmarshaling Ticket within AS_REP")
|
||||||
|
}
|
||||||
|
k.KDCRepFields = KDCRepFields{
|
||||||
|
PVNO: m.PVNO,
|
||||||
|
MsgType: m.MsgType,
|
||||||
|
PAData: m.PAData,
|
||||||
|
CRealm: m.CRealm,
|
||||||
|
CName: m.CName,
|
||||||
|
Ticket: tkt,
|
||||||
|
EncPart: m.EncPart,
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshal bytes b into the TGSRep struct.
|
||||||
|
func (k *TGSRep) Unmarshal(b []byte) error {
|
||||||
|
var m marshalKDCRep
|
||||||
|
_, err := asn1.UnmarshalWithParams(b, &m, fmt.Sprintf("application,explicit,tag:%v", asnAppTag.TGSREP))
|
||||||
|
if err != nil {
|
||||||
|
return processUnmarshalReplyError(b, err)
|
||||||
|
}
|
||||||
|
if m.MsgType != msgtype.KRB_TGS_REP {
|
||||||
|
return krberror.NewErrorf(krberror.KRBMsgError, "message ID does not indicate an TGS_REP. Expected: %v; Actual: %v", msgtype.KRB_TGS_REP, m.MsgType)
|
||||||
|
}
|
||||||
|
//Process the raw ticket within
|
||||||
|
tkt, err := unmarshalTicket(m.Ticket.Bytes)
|
||||||
|
if err != nil {
|
||||||
|
return krberror.Errorf(err, krberror.EncodingError, "error unmarshaling Ticket within TGS_REP")
|
||||||
|
}
|
||||||
|
k.KDCRepFields = KDCRepFields{
|
||||||
|
PVNO: m.PVNO,
|
||||||
|
MsgType: m.MsgType,
|
||||||
|
PAData: m.PAData,
|
||||||
|
CRealm: m.CRealm,
|
||||||
|
CName: m.CName,
|
||||||
|
Ticket: tkt,
|
||||||
|
EncPart: m.EncPart,
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshal bytes b into encrypted part of KRB_KDC_REP.
|
||||||
|
func (e *EncKDCRepPart) Unmarshal(b []byte) error {
|
||||||
|
_, err := asn1.UnmarshalWithParams(b, e, fmt.Sprintf("application,explicit,tag:%v", asnAppTag.EncASRepPart))
|
||||||
|
if err != nil {
|
||||||
|
// Try using tag 26
|
||||||
|
// Ref: RFC 4120 - mentions that some implementations use application tag number 26 wether or not the reply is
|
||||||
|
// a AS-REP or a TGS-REP.
|
||||||
|
_, err = asn1.UnmarshalWithParams(b, e, fmt.Sprintf("application,explicit,tag:%v", asnAppTag.EncTGSRepPart))
|
||||||
|
if err != nil {
|
||||||
|
return krberror.Errorf(err, krberror.EncodingError, "error unmarshaling encrypted part within KDC_REP")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecryptEncPart decrypts the encrypted part of an AS_REP.
|
||||||
|
func (k *ASRep) DecryptEncPart(c *credentials.Credentials) (types.EncryptionKey, error) {
|
||||||
|
var key types.EncryptionKey
|
||||||
|
var err error
|
||||||
|
if c.HasKeytab() {
|
||||||
|
key, _, err = c.Keytab().GetEncryptionKey(k.CName, k.CRealm, k.EncPart.KVNO, k.EncPart.EType)
|
||||||
|
if err != nil {
|
||||||
|
return key, krberror.Errorf(err, krberror.DecryptingError, "error decrypting AS_REP encrypted part")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if c.HasPassword() {
|
||||||
|
key, _, err = crypto.GetKeyFromPassword(c.Password(), k.CName, k.CRealm, k.EncPart.EType, k.PAData)
|
||||||
|
if err != nil {
|
||||||
|
return key, krberror.Errorf(err, krberror.DecryptingError, "error decrypting AS_REP encrypted part")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !c.HasKeytab() && !c.HasPassword() {
|
||||||
|
return key, krberror.NewErrorf(krberror.DecryptingError, "no secret available in credentials to perform decryption of AS_REP encrypted part")
|
||||||
|
}
|
||||||
|
b, err := crypto.DecryptEncPart(k.EncPart, key, keyusage.AS_REP_ENCPART)
|
||||||
|
if err != nil {
|
||||||
|
return key, krberror.Errorf(err, krberror.DecryptingError, "error decrypting AS_REP encrypted part")
|
||||||
|
}
|
||||||
|
var denc EncKDCRepPart
|
||||||
|
err = denc.Unmarshal(b)
|
||||||
|
if err != nil {
|
||||||
|
return key, krberror.Errorf(err, krberror.EncodingError, "error unmarshaling decrypted encpart of AS_REP")
|
||||||
|
}
|
||||||
|
k.DecryptedEncPart = denc
|
||||||
|
return key, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify checks the validity of AS_REP message.
|
||||||
|
func (k *ASRep) Verify(cfg *config.Config, creds *credentials.Credentials, asReq ASReq) (bool, error) {
|
||||||
|
//Ref RFC 4120 Section 3.1.5
|
||||||
|
if k.CName.NameType != asReq.ReqBody.CName.NameType || k.CName.NameString == nil {
|
||||||
|
return false, krberror.NewErrorf(krberror.KRBMsgError, "CName in response does not match what was requested. Requested: %+v; Reply: %+v", asReq.ReqBody.CName, k.CName)
|
||||||
|
}
|
||||||
|
for i := range k.CName.NameString {
|
||||||
|
if k.CName.NameString[i] != asReq.ReqBody.CName.NameString[i] {
|
||||||
|
return false, krberror.NewErrorf(krberror.KRBMsgError, "CName in response does not match what was requested. Requested: %+v; Reply: %+v", asReq.ReqBody.CName, k.CName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if k.CRealm != asReq.ReqBody.Realm {
|
||||||
|
return false, krberror.NewErrorf(krberror.KRBMsgError, "CRealm in response does not match what was requested. Requested: %s; Reply: %s", asReq.ReqBody.Realm, k.CRealm)
|
||||||
|
}
|
||||||
|
key, err := k.DecryptEncPart(creds)
|
||||||
|
if err != nil {
|
||||||
|
return false, krberror.Errorf(err, krberror.DecryptingError, "error decrypting EncPart of AS_REP")
|
||||||
|
}
|
||||||
|
if k.DecryptedEncPart.Nonce != asReq.ReqBody.Nonce {
|
||||||
|
return false, krberror.NewErrorf(krberror.KRBMsgError, "possible replay attack, nonce in response does not match that in request")
|
||||||
|
}
|
||||||
|
if k.DecryptedEncPart.SName.NameType != asReq.ReqBody.SName.NameType || k.DecryptedEncPart.SName.NameString == nil {
|
||||||
|
return false, krberror.NewErrorf(krberror.KRBMsgError, "SName in response does not match what was requested. Requested: %v; Reply: %v", asReq.ReqBody.SName, k.DecryptedEncPart.SName)
|
||||||
|
}
|
||||||
|
for i := range k.CName.NameString {
|
||||||
|
if k.DecryptedEncPart.SName.NameString[i] != asReq.ReqBody.SName.NameString[i] {
|
||||||
|
return false, krberror.NewErrorf(krberror.KRBMsgError, "SName in response does not match what was requested. Requested: %+v; Reply: %+v", asReq.ReqBody.SName, k.DecryptedEncPart.SName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if k.DecryptedEncPart.SRealm != asReq.ReqBody.Realm {
|
||||||
|
return false, krberror.NewErrorf(krberror.KRBMsgError, "SRealm in response does not match what was requested. Requested: %s; Reply: %s", asReq.ReqBody.Realm, k.DecryptedEncPart.SRealm)
|
||||||
|
}
|
||||||
|
if len(asReq.ReqBody.Addresses) > 0 {
|
||||||
|
if !types.HostAddressesEqual(k.DecryptedEncPart.CAddr, asReq.ReqBody.Addresses) {
|
||||||
|
return false, krberror.NewErrorf(krberror.KRBMsgError, "addresses listed in the AS_REP does not match those listed in the AS_REQ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t := time.Now().UTC()
|
||||||
|
if t.Sub(k.DecryptedEncPart.AuthTime) > cfg.LibDefaults.Clockskew || k.DecryptedEncPart.AuthTime.Sub(t) > cfg.LibDefaults.Clockskew {
|
||||||
|
return false, krberror.NewErrorf(krberror.KRBMsgError, "clock skew with KDC too large. Greater than %v seconds", cfg.LibDefaults.Clockskew.Seconds())
|
||||||
|
}
|
||||||
|
// RFC 6806 https://tools.ietf.org/html/rfc6806.html#section-11
|
||||||
|
if asReq.PAData.Contains(patype.PA_REQ_ENC_PA_REP) && types.IsFlagSet(&k.DecryptedEncPart.Flags, flags.EncPARep) {
|
||||||
|
if len(k.DecryptedEncPart.EncPAData) < 2 || !k.DecryptedEncPart.EncPAData.Contains(patype.PA_FX_FAST) {
|
||||||
|
return false, krberror.NewErrorf(krberror.KRBMsgError, "KDC did not respond appropriately to FAST negotiation")
|
||||||
|
}
|
||||||
|
for _, pa := range k.DecryptedEncPart.EncPAData {
|
||||||
|
if pa.PADataType == patype.PA_REQ_ENC_PA_REP {
|
||||||
|
var pafast types.PAReqEncPARep
|
||||||
|
err := pafast.Unmarshal(pa.PADataValue)
|
||||||
|
if err != nil {
|
||||||
|
return false, krberror.Errorf(err, krberror.EncodingError, "KDC FAST negotiation response error, could not unmarshal PA_REQ_ENC_PA_REP")
|
||||||
|
}
|
||||||
|
etype, err := crypto.GetChksumEtype(pafast.ChksumType)
|
||||||
|
if err != nil {
|
||||||
|
return false, krberror.Errorf(err, krberror.ChksumError, "KDC FAST negotiation response error")
|
||||||
|
}
|
||||||
|
ab, _ := asReq.Marshal()
|
||||||
|
if !etype.VerifyChecksum(key.KeyValue, ab, pafast.Chksum, keyusage.KEY_USAGE_AS_REQ) {
|
||||||
|
return false, krberror.Errorf(err, krberror.ChksumError, "KDC FAST negotiation response checksum invalid")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecryptEncPart decrypts the encrypted part of an TGS_REP.
|
||||||
|
func (k *TGSRep) DecryptEncPart(key types.EncryptionKey) error {
|
||||||
|
b, err := crypto.DecryptEncPart(k.EncPart, key, keyusage.TGS_REP_ENCPART_SESSION_KEY)
|
||||||
|
if err != nil {
|
||||||
|
return krberror.Errorf(err, krberror.DecryptingError, "error decrypting TGS_REP EncPart")
|
||||||
|
}
|
||||||
|
var denc EncKDCRepPart
|
||||||
|
err = denc.Unmarshal(b)
|
||||||
|
if err != nil {
|
||||||
|
return krberror.Errorf(err, krberror.EncodingError, "error unmarshaling encrypted part")
|
||||||
|
}
|
||||||
|
k.DecryptedEncPart = denc
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify checks the validity of the TGS_REP message.
|
||||||
|
func (k *TGSRep) Verify(cfg *config.Config, tgsReq TGSReq) (bool, error) {
|
||||||
|
if k.CName.NameType != tgsReq.ReqBody.CName.NameType || k.CName.NameString == nil {
|
||||||
|
return false, krberror.NewErrorf(krberror.KRBMsgError, "CName type in response does not match what was requested. Requested: %+v; Reply: %+v", tgsReq.ReqBody.CName, k.CName)
|
||||||
|
}
|
||||||
|
for i := range k.CName.NameString {
|
||||||
|
if k.CName.NameString[i] != tgsReq.ReqBody.CName.NameString[i] {
|
||||||
|
return false, krberror.NewErrorf(krberror.KRBMsgError, "CName in response does not match what was requested. Requested: %+v; Reply: %+v", tgsReq.ReqBody.CName, k.CName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if k.Ticket.Realm != tgsReq.ReqBody.Realm {
|
||||||
|
return false, krberror.NewErrorf(krberror.KRBMsgError, "realm in response ticket does not match what was requested. Requested: %s; Reply: %s", tgsReq.ReqBody.Realm, k.Ticket.Realm)
|
||||||
|
}
|
||||||
|
if k.DecryptedEncPart.Nonce != tgsReq.ReqBody.Nonce {
|
||||||
|
return false, krberror.NewErrorf(krberror.KRBMsgError, "possible replay attack, nonce in response does not match that in request")
|
||||||
|
}
|
||||||
|
//if k.Ticket.SName.NameType != tgsReq.ReqBody.SName.NameType || k.Ticket.SName.NameString == nil {
|
||||||
|
// return false, krberror.NewErrorf(krberror.KRBMsgError, "SName in response ticket does not match what was requested. Requested: %v; Reply: %v", tgsReq.ReqBody.SName, k.Ticket.SName)
|
||||||
|
//}
|
||||||
|
//for i := range k.Ticket.SName.NameString {
|
||||||
|
// if k.Ticket.SName.NameString[i] != tgsReq.ReqBody.SName.NameString[i] {
|
||||||
|
// return false, krberror.NewErrorf(krberror.KRBMsgError, "SName in response ticket does not match what was requested. Requested: %+v; Reply: %+v", tgsReq.ReqBody.SName, k.Ticket.SName)
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//if k.DecryptedEncPart.SName.NameType != tgsReq.ReqBody.SName.NameType || k.DecryptedEncPart.SName.NameString == nil {
|
||||||
|
// return false, krberror.NewErrorf(krberror.KRBMsgError, "SName in response does not match what was requested. Requested: %v; Reply: %v", tgsReq.ReqBody.SName, k.DecryptedEncPart.SName)
|
||||||
|
//}
|
||||||
|
//for i := range k.DecryptedEncPart.SName.NameString {
|
||||||
|
// if k.DecryptedEncPart.SName.NameString[i] != tgsReq.ReqBody.SName.NameString[i] {
|
||||||
|
// return false, krberror.NewErrorf(krberror.KRBMsgError, "SName in response does not match what was requested. Requested: %+v; Reply: %+v", tgsReq.ReqBody.SName, k.DecryptedEncPart.SName)
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
if k.DecryptedEncPart.SRealm != tgsReq.ReqBody.Realm {
|
||||||
|
return false, krberror.NewErrorf(krberror.KRBMsgError, "SRealm in response does not match what was requested. Requested: %s; Reply: %s", tgsReq.ReqBody.Realm, k.DecryptedEncPart.SRealm)
|
||||||
|
}
|
||||||
|
if len(k.DecryptedEncPart.CAddr) > 0 {
|
||||||
|
if !types.HostAddressesEqual(k.DecryptedEncPart.CAddr, tgsReq.ReqBody.Addresses) {
|
||||||
|
return false, krberror.NewErrorf(krberror.KRBMsgError, "addresses listed in the TGS_REP does not match those listed in the TGS_REQ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if time.Since(k.DecryptedEncPart.StartTime) > cfg.LibDefaults.Clockskew || k.DecryptedEncPart.StartTime.Sub(time.Now().UTC()) > cfg.LibDefaults.Clockskew {
|
||||||
|
if time.Since(k.DecryptedEncPart.AuthTime) > cfg.LibDefaults.Clockskew || k.DecryptedEncPart.AuthTime.Sub(time.Now().UTC()) > cfg.LibDefaults.Clockskew {
|
||||||
|
return false, krberror.NewErrorf(krberror.KRBMsgError, "clock skew with KDC too large. Greater than %v seconds.", cfg.LibDefaults.Clockskew.Seconds())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
432
vendor/github.com/jcmturner/gokrb5/v8/messages/KDCReq.go
generated
vendored
Normal file
432
vendor/github.com/jcmturner/gokrb5/v8/messages/KDCReq.go
generated
vendored
Normal file
|
@ -0,0 +1,432 @@
|
||||||
|
package messages
|
||||||
|
|
||||||
|
// Reference: https://www.ietf.org/rfc/rfc4120.txt
|
||||||
|
// Section: 5.4.1
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"math/big"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/jcmturner/gofork/encoding/asn1"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/asn1tools"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/config"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/crypto"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/asnAppTag"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/flags"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/keyusage"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/msgtype"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/nametype"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/patype"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/krberror"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
type marshalKDCReq struct {
|
||||||
|
PVNO int `asn1:"explicit,tag:1"`
|
||||||
|
MsgType int `asn1:"explicit,tag:2"`
|
||||||
|
PAData types.PADataSequence `asn1:"explicit,optional,tag:3"`
|
||||||
|
ReqBody asn1.RawValue `asn1:"explicit,tag:4"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// KDCReqFields represents the KRB_KDC_REQ fields.
|
||||||
|
type KDCReqFields struct {
|
||||||
|
PVNO int
|
||||||
|
MsgType int
|
||||||
|
PAData types.PADataSequence
|
||||||
|
ReqBody KDCReqBody
|
||||||
|
Renewal bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// ASReq implements RFC 4120 KRB_AS_REQ: https://tools.ietf.org/html/rfc4120#section-5.4.1.
|
||||||
|
type ASReq struct {
|
||||||
|
KDCReqFields
|
||||||
|
}
|
||||||
|
|
||||||
|
// TGSReq implements RFC 4120 KRB_TGS_REQ: https://tools.ietf.org/html/rfc4120#section-5.4.1.
|
||||||
|
type TGSReq struct {
|
||||||
|
KDCReqFields
|
||||||
|
}
|
||||||
|
|
||||||
|
type marshalKDCReqBody struct {
|
||||||
|
KDCOptions asn1.BitString `asn1:"explicit,tag:0"`
|
||||||
|
CName types.PrincipalName `asn1:"explicit,optional,tag:1"`
|
||||||
|
Realm string `asn1:"generalstring,explicit,tag:2"`
|
||||||
|
SName types.PrincipalName `asn1:"explicit,optional,tag:3"`
|
||||||
|
From time.Time `asn1:"generalized,explicit,optional,tag:4"`
|
||||||
|
Till time.Time `asn1:"generalized,explicit,tag:5"`
|
||||||
|
RTime time.Time `asn1:"generalized,explicit,optional,tag:6"`
|
||||||
|
Nonce int `asn1:"explicit,tag:7"`
|
||||||
|
EType []int32 `asn1:"explicit,tag:8"`
|
||||||
|
Addresses []types.HostAddress `asn1:"explicit,optional,tag:9"`
|
||||||
|
EncAuthData types.EncryptedData `asn1:"explicit,optional,tag:10"`
|
||||||
|
// Ticket needs to be a raw value as it is wrapped in an APPLICATION tag
|
||||||
|
AdditionalTickets asn1.RawValue `asn1:"explicit,optional,tag:11"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// KDCReqBody implements the KRB_KDC_REQ request body.
|
||||||
|
type KDCReqBody struct {
|
||||||
|
KDCOptions asn1.BitString `asn1:"explicit,tag:0"`
|
||||||
|
CName types.PrincipalName `asn1:"explicit,optional,tag:1"`
|
||||||
|
Realm string `asn1:"generalstring,explicit,tag:2"`
|
||||||
|
SName types.PrincipalName `asn1:"explicit,optional,tag:3"`
|
||||||
|
From time.Time `asn1:"generalized,explicit,optional,tag:4"`
|
||||||
|
Till time.Time `asn1:"generalized,explicit,tag:5"`
|
||||||
|
RTime time.Time `asn1:"generalized,explicit,optional,tag:6"`
|
||||||
|
Nonce int `asn1:"explicit,tag:7"`
|
||||||
|
EType []int32 `asn1:"explicit,tag:8"`
|
||||||
|
Addresses []types.HostAddress `asn1:"explicit,optional,tag:9"`
|
||||||
|
EncAuthData types.EncryptedData `asn1:"explicit,optional,tag:10"`
|
||||||
|
AdditionalTickets []Ticket `asn1:"explicit,optional,tag:11"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewASReqForTGT generates a new KRB_AS_REQ struct for a TGT request.
|
||||||
|
func NewASReqForTGT(realm string, c *config.Config, cname types.PrincipalName) (ASReq, error) {
|
||||||
|
sname := types.PrincipalName{
|
||||||
|
NameType: nametype.KRB_NT_SRV_INST,
|
||||||
|
NameString: []string{"krbtgt", realm},
|
||||||
|
}
|
||||||
|
return NewASReq(realm, c, cname, sname)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewASReqForChgPasswd generates a new KRB_AS_REQ struct for a change password request.
|
||||||
|
func NewASReqForChgPasswd(realm string, c *config.Config, cname types.PrincipalName) (ASReq, error) {
|
||||||
|
sname := types.PrincipalName{
|
||||||
|
NameType: nametype.KRB_NT_PRINCIPAL,
|
||||||
|
NameString: []string{"kadmin", "changepw"},
|
||||||
|
}
|
||||||
|
return NewASReq(realm, c, cname, sname)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewASReq generates a new KRB_AS_REQ struct for a given SNAME.
|
||||||
|
func NewASReq(realm string, c *config.Config, cname, sname types.PrincipalName) (ASReq, error) {
|
||||||
|
nonce, err := rand.Int(rand.Reader, big.NewInt(math.MaxInt32))
|
||||||
|
if err != nil {
|
||||||
|
return ASReq{}, err
|
||||||
|
}
|
||||||
|
t := time.Now().UTC()
|
||||||
|
// Copy the default options to make this thread safe
|
||||||
|
kopts := types.NewKrbFlags()
|
||||||
|
copy(kopts.Bytes, c.LibDefaults.KDCDefaultOptions.Bytes)
|
||||||
|
kopts.BitLength = c.LibDefaults.KDCDefaultOptions.BitLength
|
||||||
|
a := ASReq{
|
||||||
|
KDCReqFields{
|
||||||
|
PVNO: iana.PVNO,
|
||||||
|
MsgType: msgtype.KRB_AS_REQ,
|
||||||
|
PAData: types.PADataSequence{},
|
||||||
|
ReqBody: KDCReqBody{
|
||||||
|
KDCOptions: kopts,
|
||||||
|
Realm: realm,
|
||||||
|
CName: cname,
|
||||||
|
SName: sname,
|
||||||
|
Till: t.Add(c.LibDefaults.TicketLifetime),
|
||||||
|
Nonce: int(nonce.Int64()),
|
||||||
|
EType: c.LibDefaults.DefaultTktEnctypeIDs,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if c.LibDefaults.Forwardable {
|
||||||
|
types.SetFlag(&a.ReqBody.KDCOptions, flags.Forwardable)
|
||||||
|
}
|
||||||
|
if c.LibDefaults.Canonicalize {
|
||||||
|
types.SetFlag(&a.ReqBody.KDCOptions, flags.Canonicalize)
|
||||||
|
}
|
||||||
|
if c.LibDefaults.Proxiable {
|
||||||
|
types.SetFlag(&a.ReqBody.KDCOptions, flags.Proxiable)
|
||||||
|
}
|
||||||
|
if c.LibDefaults.RenewLifetime != 0 {
|
||||||
|
types.SetFlag(&a.ReqBody.KDCOptions, flags.Renewable)
|
||||||
|
a.ReqBody.RTime = t.Add(c.LibDefaults.RenewLifetime)
|
||||||
|
a.ReqBody.RTime = t.Add(time.Duration(48) * time.Hour)
|
||||||
|
}
|
||||||
|
if !c.LibDefaults.NoAddresses {
|
||||||
|
ha, err := types.LocalHostAddresses()
|
||||||
|
if err != nil {
|
||||||
|
return a, fmt.Errorf("could not get local addresses: %v", err)
|
||||||
|
}
|
||||||
|
ha = append(ha, types.HostAddressesFromNetIPs(c.LibDefaults.ExtraAddresses)...)
|
||||||
|
a.ReqBody.Addresses = ha
|
||||||
|
}
|
||||||
|
return a, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTGSReq generates a new KRB_TGS_REQ struct.
|
||||||
|
func NewTGSReq(cname types.PrincipalName, kdcRealm string, c *config.Config, tgt Ticket, sessionKey types.EncryptionKey, sname types.PrincipalName, renewal bool) (TGSReq, error) {
|
||||||
|
a, err := tgsReq(cname, sname, kdcRealm, renewal, c)
|
||||||
|
if err != nil {
|
||||||
|
return a, err
|
||||||
|
}
|
||||||
|
err = a.setPAData(tgt, sessionKey)
|
||||||
|
return a, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewUser2UserTGSReq returns a TGS-REQ suitable for user-to-user authentication (https://tools.ietf.org/html/rfc4120#section-3.7)
|
||||||
|
func NewUser2UserTGSReq(cname types.PrincipalName, kdcRealm string, c *config.Config, clientTGT Ticket, sessionKey types.EncryptionKey, sname types.PrincipalName, renewal bool, verifyingTGT Ticket) (TGSReq, error) {
|
||||||
|
a, err := tgsReq(cname, sname, kdcRealm, renewal, c)
|
||||||
|
if err != nil {
|
||||||
|
return a, err
|
||||||
|
}
|
||||||
|
a.ReqBody.AdditionalTickets = []Ticket{verifyingTGT}
|
||||||
|
types.SetFlag(&a.ReqBody.KDCOptions, flags.EncTktInSkey)
|
||||||
|
err = a.setPAData(clientTGT, sessionKey)
|
||||||
|
return a, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// tgsReq populates the fields for a TGS_REQ
|
||||||
|
func tgsReq(cname, sname types.PrincipalName, kdcRealm string, renewal bool, c *config.Config) (TGSReq, error) {
|
||||||
|
nonce, err := rand.Int(rand.Reader, big.NewInt(math.MaxInt32))
|
||||||
|
if err != nil {
|
||||||
|
return TGSReq{}, err
|
||||||
|
}
|
||||||
|
t := time.Now().UTC()
|
||||||
|
k := KDCReqFields{
|
||||||
|
PVNO: iana.PVNO,
|
||||||
|
MsgType: msgtype.KRB_TGS_REQ,
|
||||||
|
ReqBody: KDCReqBody{
|
||||||
|
KDCOptions: types.NewKrbFlags(),
|
||||||
|
Realm: kdcRealm,
|
||||||
|
CName: cname, // Add the CName to make validation of the reply easier
|
||||||
|
SName: sname,
|
||||||
|
Till: t.Add(c.LibDefaults.TicketLifetime),
|
||||||
|
Nonce: int(nonce.Int64()),
|
||||||
|
EType: c.LibDefaults.DefaultTGSEnctypeIDs,
|
||||||
|
},
|
||||||
|
Renewal: renewal,
|
||||||
|
}
|
||||||
|
if c.LibDefaults.Forwardable {
|
||||||
|
types.SetFlag(&k.ReqBody.KDCOptions, flags.Forwardable)
|
||||||
|
}
|
||||||
|
if c.LibDefaults.Canonicalize {
|
||||||
|
types.SetFlag(&k.ReqBody.KDCOptions, flags.Canonicalize)
|
||||||
|
}
|
||||||
|
if c.LibDefaults.Proxiable {
|
||||||
|
types.SetFlag(&k.ReqBody.KDCOptions, flags.Proxiable)
|
||||||
|
}
|
||||||
|
if c.LibDefaults.RenewLifetime > time.Duration(0) {
|
||||||
|
types.SetFlag(&k.ReqBody.KDCOptions, flags.Renewable)
|
||||||
|
k.ReqBody.RTime = t.Add(c.LibDefaults.RenewLifetime)
|
||||||
|
}
|
||||||
|
if !c.LibDefaults.NoAddresses {
|
||||||
|
ha, err := types.LocalHostAddresses()
|
||||||
|
if err != nil {
|
||||||
|
return TGSReq{}, fmt.Errorf("could not get local addresses: %v", err)
|
||||||
|
}
|
||||||
|
ha = append(ha, types.HostAddressesFromNetIPs(c.LibDefaults.ExtraAddresses)...)
|
||||||
|
k.ReqBody.Addresses = ha
|
||||||
|
}
|
||||||
|
if renewal {
|
||||||
|
types.SetFlag(&k.ReqBody.KDCOptions, flags.Renew)
|
||||||
|
types.SetFlag(&k.ReqBody.KDCOptions, flags.Renewable)
|
||||||
|
}
|
||||||
|
return TGSReq{
|
||||||
|
k,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k *TGSReq) setPAData(tgt Ticket, sessionKey types.EncryptionKey) error {
|
||||||
|
// Marshal the request and calculate checksum
|
||||||
|
b, err := k.ReqBody.Marshal()
|
||||||
|
if err != nil {
|
||||||
|
return krberror.Errorf(err, krberror.EncodingError, "error marshaling TGS_REQ body")
|
||||||
|
}
|
||||||
|
etype, err := crypto.GetEtype(sessionKey.KeyType)
|
||||||
|
if err != nil {
|
||||||
|
return krberror.Errorf(err, krberror.EncryptingError, "error getting etype to encrypt authenticator")
|
||||||
|
}
|
||||||
|
cb, err := etype.GetChecksumHash(sessionKey.KeyValue, b, keyusage.TGS_REQ_PA_TGS_REQ_AP_REQ_AUTHENTICATOR_CHKSUM)
|
||||||
|
if err != nil {
|
||||||
|
return krberror.Errorf(err, krberror.ChksumError, "error getting etype checksum hash")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Form PAData for TGS_REQ
|
||||||
|
// Create authenticator
|
||||||
|
auth, err := types.NewAuthenticator(tgt.Realm, k.ReqBody.CName)
|
||||||
|
if err != nil {
|
||||||
|
return krberror.Errorf(err, krberror.KRBMsgError, "error generating new authenticator")
|
||||||
|
}
|
||||||
|
auth.Cksum = types.Checksum{
|
||||||
|
CksumType: etype.GetHashID(),
|
||||||
|
Checksum: cb,
|
||||||
|
}
|
||||||
|
// Create AP_REQ
|
||||||
|
apReq, err := NewAPReq(tgt, sessionKey, auth)
|
||||||
|
if err != nil {
|
||||||
|
return krberror.Errorf(err, krberror.KRBMsgError, "error generating new AP_REQ")
|
||||||
|
}
|
||||||
|
apb, err := apReq.Marshal()
|
||||||
|
if err != nil {
|
||||||
|
return krberror.Errorf(err, krberror.EncodingError, "error marshaling AP_REQ for pre-authentication data")
|
||||||
|
}
|
||||||
|
k.PAData = types.PADataSequence{
|
||||||
|
types.PAData{
|
||||||
|
PADataType: patype.PA_TGS_REQ,
|
||||||
|
PADataValue: apb,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshal bytes b into the ASReq struct.
|
||||||
|
func (k *ASReq) Unmarshal(b []byte) error {
|
||||||
|
var m marshalKDCReq
|
||||||
|
_, err := asn1.UnmarshalWithParams(b, &m, fmt.Sprintf("application,explicit,tag:%v", asnAppTag.ASREQ))
|
||||||
|
if err != nil {
|
||||||
|
return krberror.Errorf(err, krberror.EncodingError, "error unmarshaling AS_REQ")
|
||||||
|
}
|
||||||
|
expectedMsgType := msgtype.KRB_AS_REQ
|
||||||
|
if m.MsgType != expectedMsgType {
|
||||||
|
return krberror.NewErrorf(krberror.KRBMsgError, "message ID does not indicate a AS_REQ. Expected: %v; Actual: %v", expectedMsgType, m.MsgType)
|
||||||
|
}
|
||||||
|
var reqb KDCReqBody
|
||||||
|
err = reqb.Unmarshal(m.ReqBody.Bytes)
|
||||||
|
if err != nil {
|
||||||
|
return krberror.Errorf(err, krberror.EncodingError, "error processing AS_REQ body")
|
||||||
|
}
|
||||||
|
k.MsgType = m.MsgType
|
||||||
|
k.PAData = m.PAData
|
||||||
|
k.PVNO = m.PVNO
|
||||||
|
k.ReqBody = reqb
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshal bytes b into the TGSReq struct.
|
||||||
|
func (k *TGSReq) Unmarshal(b []byte) error {
|
||||||
|
var m marshalKDCReq
|
||||||
|
_, err := asn1.UnmarshalWithParams(b, &m, fmt.Sprintf("application,explicit,tag:%v", asnAppTag.TGSREQ))
|
||||||
|
if err != nil {
|
||||||
|
return krberror.Errorf(err, krberror.EncodingError, "error unmarshaling TGS_REQ")
|
||||||
|
}
|
||||||
|
expectedMsgType := msgtype.KRB_TGS_REQ
|
||||||
|
if m.MsgType != expectedMsgType {
|
||||||
|
return krberror.NewErrorf(krberror.KRBMsgError, "message ID does not indicate a TGS_REQ. Expected: %v; Actual: %v", expectedMsgType, m.MsgType)
|
||||||
|
}
|
||||||
|
var reqb KDCReqBody
|
||||||
|
err = reqb.Unmarshal(m.ReqBody.Bytes)
|
||||||
|
if err != nil {
|
||||||
|
return krberror.Errorf(err, krberror.EncodingError, "error processing TGS_REQ body")
|
||||||
|
}
|
||||||
|
k.MsgType = m.MsgType
|
||||||
|
k.PAData = m.PAData
|
||||||
|
k.PVNO = m.PVNO
|
||||||
|
k.ReqBody = reqb
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshal bytes b into the KRB_KDC_REQ body struct.
|
||||||
|
func (k *KDCReqBody) Unmarshal(b []byte) error {
|
||||||
|
var m marshalKDCReqBody
|
||||||
|
_, err := asn1.Unmarshal(b, &m)
|
||||||
|
if err != nil {
|
||||||
|
return krberror.Errorf(err, krberror.EncodingError, "error unmarshaling KDC_REQ body")
|
||||||
|
}
|
||||||
|
k.KDCOptions = m.KDCOptions
|
||||||
|
if len(k.KDCOptions.Bytes) < 4 {
|
||||||
|
tb := make([]byte, 4-len(k.KDCOptions.Bytes))
|
||||||
|
k.KDCOptions.Bytes = append(tb, k.KDCOptions.Bytes...)
|
||||||
|
k.KDCOptions.BitLength = len(k.KDCOptions.Bytes) * 8
|
||||||
|
}
|
||||||
|
k.CName = m.CName
|
||||||
|
k.Realm = m.Realm
|
||||||
|
k.SName = m.SName
|
||||||
|
k.From = m.From
|
||||||
|
k.Till = m.Till
|
||||||
|
k.RTime = m.RTime
|
||||||
|
k.Nonce = m.Nonce
|
||||||
|
k.EType = m.EType
|
||||||
|
k.Addresses = m.Addresses
|
||||||
|
k.EncAuthData = m.EncAuthData
|
||||||
|
if len(m.AdditionalTickets.Bytes) > 0 {
|
||||||
|
k.AdditionalTickets, err = unmarshalTicketsSequence(m.AdditionalTickets)
|
||||||
|
if err != nil {
|
||||||
|
return krberror.Errorf(err, krberror.EncodingError, "error unmarshaling additional tickets")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marshal ASReq struct.
|
||||||
|
func (k *ASReq) Marshal() ([]byte, error) {
|
||||||
|
m := marshalKDCReq{
|
||||||
|
PVNO: k.PVNO,
|
||||||
|
MsgType: k.MsgType,
|
||||||
|
PAData: k.PAData,
|
||||||
|
}
|
||||||
|
b, err := k.ReqBody.Marshal()
|
||||||
|
if err != nil {
|
||||||
|
var mk []byte
|
||||||
|
return mk, err
|
||||||
|
}
|
||||||
|
m.ReqBody = asn1.RawValue{
|
||||||
|
Class: asn1.ClassContextSpecific,
|
||||||
|
IsCompound: true,
|
||||||
|
Tag: 4,
|
||||||
|
Bytes: b,
|
||||||
|
}
|
||||||
|
mk, err := asn1.Marshal(m)
|
||||||
|
if err != nil {
|
||||||
|
return mk, krberror.Errorf(err, krberror.EncodingError, "error marshaling AS_REQ")
|
||||||
|
}
|
||||||
|
mk = asn1tools.AddASNAppTag(mk, asnAppTag.ASREQ)
|
||||||
|
return mk, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marshal TGSReq struct.
|
||||||
|
func (k *TGSReq) Marshal() ([]byte, error) {
|
||||||
|
m := marshalKDCReq{
|
||||||
|
PVNO: k.PVNO,
|
||||||
|
MsgType: k.MsgType,
|
||||||
|
PAData: k.PAData,
|
||||||
|
}
|
||||||
|
b, err := k.ReqBody.Marshal()
|
||||||
|
if err != nil {
|
||||||
|
var mk []byte
|
||||||
|
return mk, err
|
||||||
|
}
|
||||||
|
m.ReqBody = asn1.RawValue{
|
||||||
|
Class: asn1.ClassContextSpecific,
|
||||||
|
IsCompound: true,
|
||||||
|
Tag: 4,
|
||||||
|
Bytes: b,
|
||||||
|
}
|
||||||
|
mk, err := asn1.Marshal(m)
|
||||||
|
if err != nil {
|
||||||
|
return mk, krberror.Errorf(err, krberror.EncodingError, "error marshaling AS_REQ")
|
||||||
|
}
|
||||||
|
mk = asn1tools.AddASNAppTag(mk, asnAppTag.TGSREQ)
|
||||||
|
return mk, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marshal KRB_KDC_REQ body struct.
|
||||||
|
func (k *KDCReqBody) Marshal() ([]byte, error) {
|
||||||
|
var b []byte
|
||||||
|
m := marshalKDCReqBody{
|
||||||
|
KDCOptions: k.KDCOptions,
|
||||||
|
CName: k.CName,
|
||||||
|
Realm: k.Realm,
|
||||||
|
SName: k.SName,
|
||||||
|
From: k.From,
|
||||||
|
Till: k.Till,
|
||||||
|
RTime: k.RTime,
|
||||||
|
Nonce: k.Nonce,
|
||||||
|
EType: k.EType,
|
||||||
|
Addresses: k.Addresses,
|
||||||
|
EncAuthData: k.EncAuthData,
|
||||||
|
}
|
||||||
|
rawtkts, err := MarshalTicketSequence(k.AdditionalTickets)
|
||||||
|
if err != nil {
|
||||||
|
return b, krberror.Errorf(err, krberror.EncodingError, "error in marshaling KDC request body additional tickets")
|
||||||
|
}
|
||||||
|
//The asn1.rawValue needs the tag setting on it for where it is in the KDCReqBody
|
||||||
|
rawtkts.Tag = 11
|
||||||
|
if len(rawtkts.Bytes) > 0 {
|
||||||
|
m.AdditionalTickets = rawtkts
|
||||||
|
}
|
||||||
|
b, err = asn1.Marshal(m)
|
||||||
|
if err != nil {
|
||||||
|
return b, krberror.Errorf(err, krberror.EncodingError, "error in marshaling KDC request body")
|
||||||
|
}
|
||||||
|
return b, nil
|
||||||
|
}
|
102
vendor/github.com/jcmturner/gokrb5/v8/messages/KRBCred.go
generated
vendored
Normal file
102
vendor/github.com/jcmturner/gokrb5/v8/messages/KRBCred.go
generated
vendored
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
package messages
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/jcmturner/gofork/encoding/asn1"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/crypto"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/asnAppTag"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/keyusage"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/msgtype"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/krberror"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
type marshalKRBCred struct {
|
||||||
|
PVNO int `asn1:"explicit,tag:0"`
|
||||||
|
MsgType int `asn1:"explicit,tag:1"`
|
||||||
|
Tickets asn1.RawValue `asn1:"explicit,tag:2"`
|
||||||
|
EncPart types.EncryptedData `asn1:"explicit,tag:3"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// KRBCred implements RFC 4120 KRB_CRED: https://tools.ietf.org/html/rfc4120#section-5.8.1.
|
||||||
|
type KRBCred struct {
|
||||||
|
PVNO int
|
||||||
|
MsgType int
|
||||||
|
Tickets []Ticket
|
||||||
|
EncPart types.EncryptedData
|
||||||
|
DecryptedEncPart EncKrbCredPart
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncKrbCredPart is the encrypted part of KRB_CRED.
|
||||||
|
type EncKrbCredPart struct {
|
||||||
|
TicketInfo []KrbCredInfo `asn1:"explicit,tag:0"`
|
||||||
|
Nouce int `asn1:"optional,explicit,tag:1"`
|
||||||
|
Timestamp time.Time `asn1:"generalized,optional,explicit,tag:2"`
|
||||||
|
Usec int `asn1:"optional,explicit,tag:3"`
|
||||||
|
SAddress types.HostAddress `asn1:"optional,explicit,tag:4"`
|
||||||
|
RAddress types.HostAddress `asn1:"optional,explicit,tag:5"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// KrbCredInfo is the KRB_CRED_INFO part of KRB_CRED.
|
||||||
|
type KrbCredInfo struct {
|
||||||
|
Key types.EncryptionKey `asn1:"explicit,tag:0"`
|
||||||
|
PRealm string `asn1:"generalstring,optional,explicit,tag:1"`
|
||||||
|
PName types.PrincipalName `asn1:"optional,explicit,tag:2"`
|
||||||
|
Flags asn1.BitString `asn1:"optional,explicit,tag:3"`
|
||||||
|
AuthTime time.Time `asn1:"generalized,optional,explicit,tag:4"`
|
||||||
|
StartTime time.Time `asn1:"generalized,optional,explicit,tag:5"`
|
||||||
|
EndTime time.Time `asn1:"generalized,optional,explicit,tag:6"`
|
||||||
|
RenewTill time.Time `asn1:"generalized,optional,explicit,tag:7"`
|
||||||
|
SRealm string `asn1:"optional,explicit,ia5,tag:8"`
|
||||||
|
SName types.PrincipalName `asn1:"optional,explicit,tag:9"`
|
||||||
|
CAddr types.HostAddresses `asn1:"optional,explicit,tag:10"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshal bytes b into the KRBCred struct.
|
||||||
|
func (k *KRBCred) Unmarshal(b []byte) error {
|
||||||
|
var m marshalKRBCred
|
||||||
|
_, err := asn1.UnmarshalWithParams(b, &m, fmt.Sprintf("application,explicit,tag:%v", asnAppTag.KRBCred))
|
||||||
|
if err != nil {
|
||||||
|
return processUnmarshalReplyError(b, err)
|
||||||
|
}
|
||||||
|
expectedMsgType := msgtype.KRB_CRED
|
||||||
|
if m.MsgType != expectedMsgType {
|
||||||
|
return krberror.NewErrorf(krberror.KRBMsgError, "message ID does not indicate a KRB_CRED. Expected: %v; Actual: %v", expectedMsgType, m.MsgType)
|
||||||
|
}
|
||||||
|
k.PVNO = m.PVNO
|
||||||
|
k.MsgType = m.MsgType
|
||||||
|
k.EncPart = m.EncPart
|
||||||
|
if len(m.Tickets.Bytes) > 0 {
|
||||||
|
k.Tickets, err = unmarshalTicketsSequence(m.Tickets)
|
||||||
|
if err != nil {
|
||||||
|
return krberror.Errorf(err, krberror.EncodingError, "error unmarshaling tickets within KRB_CRED")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecryptEncPart decrypts the encrypted part of a KRB_CRED.
|
||||||
|
func (k *KRBCred) DecryptEncPart(key types.EncryptionKey) error {
|
||||||
|
b, err := crypto.DecryptEncPart(k.EncPart, key, keyusage.KRB_CRED_ENCPART)
|
||||||
|
if err != nil {
|
||||||
|
return krberror.Errorf(err, krberror.DecryptingError, "error decrypting KRB_CRED EncPart")
|
||||||
|
}
|
||||||
|
var denc EncKrbCredPart
|
||||||
|
err = denc.Unmarshal(b)
|
||||||
|
if err != nil {
|
||||||
|
return krberror.Errorf(err, krberror.EncodingError, "error unmarshaling encrypted part of KRB_CRED")
|
||||||
|
}
|
||||||
|
k.DecryptedEncPart = denc
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshal bytes b into the encrypted part of KRB_CRED.
|
||||||
|
func (k *EncKrbCredPart) Unmarshal(b []byte) error {
|
||||||
|
_, err := asn1.UnmarshalWithParams(b, k, fmt.Sprintf("application,explicit,tag:%v", asnAppTag.EncKrbCredPart))
|
||||||
|
if err != nil {
|
||||||
|
return krberror.Errorf(err, krberror.EncodingError, "error unmarshaling EncKrbCredPart")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
83
vendor/github.com/jcmturner/gokrb5/v8/messages/KRBError.go
generated
vendored
Normal file
83
vendor/github.com/jcmturner/gokrb5/v8/messages/KRBError.go
generated
vendored
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
// Package messages implements Kerberos 5 message types and methods.
|
||||||
|
package messages
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/jcmturner/gofork/encoding/asn1"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/asnAppTag"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/errorcode"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/msgtype"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/krberror"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// KRBError implements RFC 4120 KRB_ERROR: https://tools.ietf.org/html/rfc4120#section-5.9.1.
|
||||||
|
type KRBError struct {
|
||||||
|
PVNO int `asn1:"explicit,tag:0"`
|
||||||
|
MsgType int `asn1:"explicit,tag:1"`
|
||||||
|
CTime time.Time `asn1:"generalized,optional,explicit,tag:2"`
|
||||||
|
Cusec int `asn1:"optional,explicit,tag:3"`
|
||||||
|
STime time.Time `asn1:"generalized,explicit,tag:4"`
|
||||||
|
Susec int `asn1:"explicit,tag:5"`
|
||||||
|
ErrorCode int32 `asn1:"explicit,tag:6"`
|
||||||
|
CRealm string `asn1:"generalstring,optional,explicit,tag:7"`
|
||||||
|
CName types.PrincipalName `asn1:"optional,explicit,tag:8"`
|
||||||
|
Realm string `asn1:"generalstring,explicit,tag:9"`
|
||||||
|
SName types.PrincipalName `asn1:"explicit,tag:10"`
|
||||||
|
EText string `asn1:"generalstring,optional,explicit,tag:11"`
|
||||||
|
EData []byte `asn1:"optional,explicit,tag:12"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewKRBError creates a new KRBError.
|
||||||
|
func NewKRBError(sname types.PrincipalName, realm string, code int32, etext string) KRBError {
|
||||||
|
t := time.Now().UTC()
|
||||||
|
return KRBError{
|
||||||
|
PVNO: iana.PVNO,
|
||||||
|
MsgType: msgtype.KRB_ERROR,
|
||||||
|
STime: t,
|
||||||
|
Susec: int((t.UnixNano() / int64(time.Microsecond)) - (t.Unix() * 1e6)),
|
||||||
|
ErrorCode: code,
|
||||||
|
SName: sname,
|
||||||
|
Realm: realm,
|
||||||
|
EText: etext,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshal bytes b into the KRBError struct.
|
||||||
|
func (k *KRBError) Unmarshal(b []byte) error {
|
||||||
|
_, err := asn1.UnmarshalWithParams(b, k, fmt.Sprintf("application,explicit,tag:%v", asnAppTag.KRBError))
|
||||||
|
if err != nil {
|
||||||
|
return krberror.Errorf(err, krberror.EncodingError, "KRB_ERROR unmarshal error")
|
||||||
|
}
|
||||||
|
expectedMsgType := msgtype.KRB_ERROR
|
||||||
|
if k.MsgType != expectedMsgType {
|
||||||
|
return krberror.NewErrorf(krberror.KRBMsgError, "message ID does not indicate a KRB_ERROR. Expected: %v; Actual: %v", expectedMsgType, k.MsgType)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error method implementing error interface on KRBError struct.
|
||||||
|
func (k KRBError) Error() string {
|
||||||
|
etxt := fmt.Sprintf("KRB Error: %s", errorcode.Lookup(k.ErrorCode))
|
||||||
|
if k.EText != "" {
|
||||||
|
etxt = fmt.Sprintf("%s - %s", etxt, k.EText)
|
||||||
|
}
|
||||||
|
return etxt
|
||||||
|
}
|
||||||
|
|
||||||
|
func processUnmarshalReplyError(b []byte, err error) error {
|
||||||
|
switch err.(type) {
|
||||||
|
case asn1.StructuralError:
|
||||||
|
var krberr KRBError
|
||||||
|
tmperr := krberr.Unmarshal(b)
|
||||||
|
if tmperr != nil {
|
||||||
|
return krberror.Errorf(err, krberror.EncodingError, "failed to unmarshal KDC's reply")
|
||||||
|
}
|
||||||
|
return krberr
|
||||||
|
default:
|
||||||
|
return krberror.Errorf(err, krberror.EncodingError, "failed to unmarshal KDC's reply")
|
||||||
|
}
|
||||||
|
}
|
108
vendor/github.com/jcmturner/gokrb5/v8/messages/KRBPriv.go
generated
vendored
Normal file
108
vendor/github.com/jcmturner/gokrb5/v8/messages/KRBPriv.go
generated
vendored
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
package messages
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/jcmturner/gofork/encoding/asn1"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/asn1tools"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/crypto"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/asnAppTag"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/keyusage"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/iana/msgtype"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/krberror"
|
||||||
|
"github.com/jcmturner/gokrb5/v8/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// KRBPriv implements RFC 4120 type: https://tools.ietf.org/html/rfc4120#section-5.7.1.
|
||||||
|
type KRBPriv struct {
|
||||||
|
PVNO int `asn1:"explicit,tag:0"`
|
||||||
|
MsgType int `asn1:"explicit,tag:1"`
|
||||||
|
EncPart types.EncryptedData `asn1:"explicit,tag:3"`
|
||||||
|
DecryptedEncPart EncKrbPrivPart `asn1:"optional,omitempty"` // Not part of ASN1 bytes so marked as optional so unmarshalling works
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncKrbPrivPart is the encrypted part of KRB_PRIV.
|
||||||
|
type EncKrbPrivPart struct {
|
||||||
|
UserData []byte `asn1:"explicit,tag:0"`
|
||||||
|
Timestamp time.Time `asn1:"generalized,optional,explicit,tag:1"`
|
||||||
|
Usec int `asn1:"optional,explicit,tag:2"`
|
||||||
|
SequenceNumber int64 `asn1:"optional,explicit,tag:3"`
|
||||||
|
SAddress types.HostAddress `asn1:"explicit,tag:4"`
|
||||||
|
RAddress types.HostAddress `asn1:"optional,explicit,tag:5"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewKRBPriv returns a new KRBPriv type.
|
||||||
|
func NewKRBPriv(part EncKrbPrivPart) KRBPriv {
|
||||||
|
return KRBPriv{
|
||||||
|
PVNO: iana.PVNO,
|
||||||
|
MsgType: msgtype.KRB_PRIV,
|
||||||
|
DecryptedEncPart: part,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshal bytes b into the KRBPriv struct.
|
||||||
|
func (k *KRBPriv) Unmarshal(b []byte) error {
|
||||||
|
_, err := asn1.UnmarshalWithParams(b, k, fmt.Sprintf("application,explicit,tag:%v", asnAppTag.KRBPriv))
|
||||||
|
if err != nil {
|
||||||
|
return processUnmarshalReplyError(b, err)
|
||||||
|
}
|
||||||
|
expectedMsgType := msgtype.KRB_PRIV
|
||||||
|
if k.MsgType != expectedMsgType {
|
||||||
|
return krberror.NewErrorf(krberror.KRBMsgError, "message ID does not indicate a KRB_PRIV. Expected: %v; Actual: %v", expectedMsgType, k.MsgType)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshal bytes b into the EncKrbPrivPart struct.
|
||||||
|
func (k *EncKrbPrivPart) Unmarshal(b []byte) error {
|
||||||
|
_, err := asn1.UnmarshalWithParams(b, k, fmt.Sprintf("application,explicit,tag:%v", asnAppTag.EncKrbPrivPart))
|
||||||
|
if err != nil {
|
||||||
|
return krberror.Errorf(err, krberror.EncodingError, "KRB_PRIV unmarshal error")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marshal the KRBPriv.
|
||||||
|
func (k *KRBPriv) Marshal() ([]byte, error) {
|
||||||
|
tk := KRBPriv{
|
||||||
|
PVNO: k.PVNO,
|
||||||
|
MsgType: k.MsgType,
|
||||||
|
EncPart: k.EncPart,
|
||||||
|
}
|
||||||
|
b, err := asn1.Marshal(tk)
|
||||||
|
if err != nil {
|
||||||
|
return []byte{}, err
|
||||||
|
}
|
||||||
|
b = asn1tools.AddASNAppTag(b, asnAppTag.KRBPriv)
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncryptEncPart encrypts the DecryptedEncPart within the KRBPriv.
|
||||||
|
// Use to prepare for marshaling.
|
||||||
|
func (k *KRBPriv) EncryptEncPart(key types.EncryptionKey) error {
|
||||||
|
b, err := asn1.Marshal(k.DecryptedEncPart)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
b = asn1tools.AddASNAppTag(b, asnAppTag.EncKrbPrivPart)
|
||||||
|
k.EncPart, err = crypto.GetEncryptedData(b, key, keyusage.KRB_PRIV_ENCPART, 1)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecryptEncPart decrypts the encrypted part of the KRBPriv message.
|
||||||
|
func (k *KRBPriv) DecryptEncPart(key types.EncryptionKey) error {
|
||||||
|
b, err := crypto.DecryptEncPart(k.EncPart, key, keyusage.KRB_PRIV_ENCPART)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error decrypting KRBPriv EncPart: %v", err)
|
||||||
|
}
|
||||||
|
err = k.DecryptedEncPart.Unmarshal(b)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error unmarshaling encrypted part: %v", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue