Update module lib/pq to v1.6.0 (#572)

Update module lib/pq to v1.6.0

Reviewed-on: vikunja/api#572
This commit is contained in:
renovate 2020-05-29 17:47:28 +00:00 committed by konrad
parent 5a04f1ecf4
commit 54b18b3c59
161 changed files with 19472 additions and 7 deletions

2
go.mod
View File

@ -44,7 +44,7 @@ require (
github.com/labstack/echo/v4 v4.1.16
github.com/labstack/gommon v0.3.0
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/mattn/go-sqlite3 v2.0.3+incompatible
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect

28
go.sum
View File

@ -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/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/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/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=
@ -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/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/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.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
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-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.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/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=
@ -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/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ=
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/go.mod h1:+MhJ+VPZMpv8Ui6WRzpJFuWFKxBCZgVOo5HAmlw1sFc=
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.5.2 h1:yTSXVswvWUOQ3k1sd7vJfDrbSl8lKuscqFJRqjC0ifw=
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/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
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/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-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/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
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-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-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/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
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/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
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/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
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
View 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
View 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
View 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
View 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

View 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
View 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
View 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
View 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
View 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
View 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
View 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
View File

@ -0,0 +1 @@
module github.com/hashicorp/go-uuid

83
vendor/github.com/hashicorp/go-uuid/uuid.go generated vendored Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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.

View 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

File diff suppressed because it is too large Load Diff

View 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
}

View 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
}

View 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
View 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
View 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"
```

View 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
View 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
View 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
View 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
View 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
View 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.

View 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
}
*/

View 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
}

View 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
View 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
View 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
View 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
View 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
View 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])
}

View 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
View 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
View 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
}

View 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
}

View 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
}

View 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
}

View 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)
}

View 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)
}

View 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)
}

View 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
}