update vendor directory
This commit is contained in:
parent
37931c551f
commit
0694f2635b
46
vendor/github.com/Azure/azure-sdk-for-go/profiles/latest/compute/mgmt/compute/computeapi/models.go
generated
vendored
Normal file
46
vendor/github.com/Azure/azure-sdk-for-go/profiles/latest/compute/mgmt/compute/computeapi/models.go
generated
vendored
Normal file
|
@ -0,0 +1,46 @@
|
|||
// +build go1.9
|
||||
|
||||
// Copyright 2019 Microsoft Corporation
|
||||
//
|
||||
// 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.
|
||||
|
||||
// This code was auto-generated by:
|
||||
// github.com/Azure/azure-sdk-for-go/tools/profileBuilder
|
||||
|
||||
package computeapi
|
||||
|
||||
import original "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-03-01/compute/computeapi"
|
||||
|
||||
type AvailabilitySetsClientAPI = original.AvailabilitySetsClientAPI
|
||||
type ContainerServicesClientAPI = original.ContainerServicesClientAPI
|
||||
type DisksClientAPI = original.DisksClientAPI
|
||||
type GalleriesClientAPI = original.GalleriesClientAPI
|
||||
type GalleryImageVersionsClientAPI = original.GalleryImageVersionsClientAPI
|
||||
type GalleryImagesClientAPI = original.GalleryImagesClientAPI
|
||||
type ImagesClientAPI = original.ImagesClientAPI
|
||||
type LogAnalyticsClientAPI = original.LogAnalyticsClientAPI
|
||||
type OperationsClientAPI = original.OperationsClientAPI
|
||||
type ProximityPlacementGroupsClientAPI = original.ProximityPlacementGroupsClientAPI
|
||||
type ResourceSkusClientAPI = original.ResourceSkusClientAPI
|
||||
type SnapshotsClientAPI = original.SnapshotsClientAPI
|
||||
type UsageClientAPI = original.UsageClientAPI
|
||||
type VirtualMachineExtensionImagesClientAPI = original.VirtualMachineExtensionImagesClientAPI
|
||||
type VirtualMachineExtensionsClientAPI = original.VirtualMachineExtensionsClientAPI
|
||||
type VirtualMachineImagesClientAPI = original.VirtualMachineImagesClientAPI
|
||||
type VirtualMachineRunCommandsClientAPI = original.VirtualMachineRunCommandsClientAPI
|
||||
type VirtualMachineScaleSetExtensionsClientAPI = original.VirtualMachineScaleSetExtensionsClientAPI
|
||||
type VirtualMachineScaleSetRollingUpgradesClientAPI = original.VirtualMachineScaleSetRollingUpgradesClientAPI
|
||||
type VirtualMachineScaleSetVMsClientAPI = original.VirtualMachineScaleSetVMsClientAPI
|
||||
type VirtualMachineScaleSetsClientAPI = original.VirtualMachineScaleSetsClientAPI
|
||||
type VirtualMachineSizesClientAPI = original.VirtualMachineSizesClientAPI
|
||||
type VirtualMachinesClientAPI = original.VirtualMachinesClientAPI
|
1397
vendor/github.com/Azure/azure-sdk-for-go/profiles/latest/compute/mgmt/compute/models.go
generated
vendored
Normal file
1397
vendor/github.com/Azure/azure-sdk-for-go/profiles/latest/compute/mgmt/compute/models.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
299
vendor/github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-03-01/compute/computeapi/interfaces.go
generated
vendored
Normal file
299
vendor/github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-03-01/compute/computeapi/interfaces.go
generated
vendored
Normal file
|
@ -0,0 +1,299 @@
|
|||
package computeapi
|
||||
|
||||
// Copyright (c) Microsoft and contributors. All rights reserved.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// Code generated by Microsoft (R) AutoRest Code Generator.
|
||||
// Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-03-01/compute"
|
||||
"github.com/Azure/go-autorest/autorest"
|
||||
)
|
||||
|
||||
// OperationsClientAPI contains the set of methods on the OperationsClient type.
|
||||
type OperationsClientAPI interface {
|
||||
List(ctx context.Context) (result compute.OperationListResult, err error)
|
||||
}
|
||||
|
||||
var _ OperationsClientAPI = (*compute.OperationsClient)(nil)
|
||||
|
||||
// AvailabilitySetsClientAPI contains the set of methods on the AvailabilitySetsClient type.
|
||||
type AvailabilitySetsClientAPI interface {
|
||||
CreateOrUpdate(ctx context.Context, resourceGroupName string, availabilitySetName string, parameters compute.AvailabilitySet) (result compute.AvailabilitySet, err error)
|
||||
Delete(ctx context.Context, resourceGroupName string, availabilitySetName string) (result autorest.Response, err error)
|
||||
Get(ctx context.Context, resourceGroupName string, availabilitySetName string) (result compute.AvailabilitySet, err error)
|
||||
List(ctx context.Context, resourceGroupName string) (result compute.AvailabilitySetListResultPage, err error)
|
||||
ListAvailableSizes(ctx context.Context, resourceGroupName string, availabilitySetName string) (result compute.VirtualMachineSizeListResult, err error)
|
||||
ListBySubscription(ctx context.Context) (result compute.AvailabilitySetListResultPage, err error)
|
||||
Update(ctx context.Context, resourceGroupName string, availabilitySetName string, parameters compute.AvailabilitySetUpdate) (result compute.AvailabilitySet, err error)
|
||||
}
|
||||
|
||||
var _ AvailabilitySetsClientAPI = (*compute.AvailabilitySetsClient)(nil)
|
||||
|
||||
// ProximityPlacementGroupsClientAPI contains the set of methods on the ProximityPlacementGroupsClient type.
|
||||
type ProximityPlacementGroupsClientAPI interface {
|
||||
CreateOrUpdate(ctx context.Context, resourceGroupName string, proximityPlacementGroupName string, parameters compute.ProximityPlacementGroup) (result compute.ProximityPlacementGroup, err error)
|
||||
Delete(ctx context.Context, resourceGroupName string, proximityPlacementGroupName string) (result autorest.Response, err error)
|
||||
Get(ctx context.Context, resourceGroupName string, proximityPlacementGroupName string) (result compute.ProximityPlacementGroup, err error)
|
||||
ListByResourceGroup(ctx context.Context, resourceGroupName string) (result compute.ProximityPlacementGroupListResultPage, err error)
|
||||
ListBySubscription(ctx context.Context) (result compute.ProximityPlacementGroupListResultPage, err error)
|
||||
Update(ctx context.Context, resourceGroupName string, proximityPlacementGroupName string, parameters compute.ProximityPlacementGroupUpdate) (result compute.ProximityPlacementGroup, err error)
|
||||
}
|
||||
|
||||
var _ ProximityPlacementGroupsClientAPI = (*compute.ProximityPlacementGroupsClient)(nil)
|
||||
|
||||
// VirtualMachineExtensionImagesClientAPI contains the set of methods on the VirtualMachineExtensionImagesClient type.
|
||||
type VirtualMachineExtensionImagesClientAPI interface {
|
||||
Get(ctx context.Context, location string, publisherName string, typeParameter string, version string) (result compute.VirtualMachineExtensionImage, err error)
|
||||
ListTypes(ctx context.Context, location string, publisherName string) (result compute.ListVirtualMachineExtensionImage, err error)
|
||||
ListVersions(ctx context.Context, location string, publisherName string, typeParameter string, filter string, top *int32, orderby string) (result compute.ListVirtualMachineExtensionImage, err error)
|
||||
}
|
||||
|
||||
var _ VirtualMachineExtensionImagesClientAPI = (*compute.VirtualMachineExtensionImagesClient)(nil)
|
||||
|
||||
// VirtualMachineExtensionsClientAPI contains the set of methods on the VirtualMachineExtensionsClient type.
|
||||
type VirtualMachineExtensionsClientAPI interface {
|
||||
CreateOrUpdate(ctx context.Context, resourceGroupName string, VMName string, VMExtensionName string, extensionParameters compute.VirtualMachineExtension) (result compute.VirtualMachineExtensionsCreateOrUpdateFuture, err error)
|
||||
Delete(ctx context.Context, resourceGroupName string, VMName string, VMExtensionName string) (result compute.VirtualMachineExtensionsDeleteFuture, err error)
|
||||
Get(ctx context.Context, resourceGroupName string, VMName string, VMExtensionName string, expand string) (result compute.VirtualMachineExtension, err error)
|
||||
List(ctx context.Context, resourceGroupName string, VMName string, expand string) (result compute.VirtualMachineExtensionsListResult, err error)
|
||||
Update(ctx context.Context, resourceGroupName string, VMName string, VMExtensionName string, extensionParameters compute.VirtualMachineExtensionUpdate) (result compute.VirtualMachineExtensionsUpdateFuture, err error)
|
||||
}
|
||||
|
||||
var _ VirtualMachineExtensionsClientAPI = (*compute.VirtualMachineExtensionsClient)(nil)
|
||||
|
||||
// VirtualMachineImagesClientAPI contains the set of methods on the VirtualMachineImagesClient type.
|
||||
type VirtualMachineImagesClientAPI interface {
|
||||
Get(ctx context.Context, location string, publisherName string, offer string, skus string, version string) (result compute.VirtualMachineImage, err error)
|
||||
List(ctx context.Context, location string, publisherName string, offer string, skus string, filter string, top *int32, orderby string) (result compute.ListVirtualMachineImageResource, err error)
|
||||
ListOffers(ctx context.Context, location string, publisherName string) (result compute.ListVirtualMachineImageResource, err error)
|
||||
ListPublishers(ctx context.Context, location string) (result compute.ListVirtualMachineImageResource, err error)
|
||||
ListSkus(ctx context.Context, location string, publisherName string, offer string) (result compute.ListVirtualMachineImageResource, err error)
|
||||
}
|
||||
|
||||
var _ VirtualMachineImagesClientAPI = (*compute.VirtualMachineImagesClient)(nil)
|
||||
|
||||
// UsageClientAPI contains the set of methods on the UsageClient type.
|
||||
type UsageClientAPI interface {
|
||||
List(ctx context.Context, location string) (result compute.ListUsagesResultPage, err error)
|
||||
}
|
||||
|
||||
var _ UsageClientAPI = (*compute.UsageClient)(nil)
|
||||
|
||||
// VirtualMachinesClientAPI contains the set of methods on the VirtualMachinesClient type.
|
||||
type VirtualMachinesClientAPI interface {
|
||||
Capture(ctx context.Context, resourceGroupName string, VMName string, parameters compute.VirtualMachineCaptureParameters) (result compute.VirtualMachinesCaptureFuture, err error)
|
||||
ConvertToManagedDisks(ctx context.Context, resourceGroupName string, VMName string) (result compute.VirtualMachinesConvertToManagedDisksFuture, err error)
|
||||
CreateOrUpdate(ctx context.Context, resourceGroupName string, VMName string, parameters compute.VirtualMachine) (result compute.VirtualMachinesCreateOrUpdateFuture, err error)
|
||||
Deallocate(ctx context.Context, resourceGroupName string, VMName string) (result compute.VirtualMachinesDeallocateFuture, err error)
|
||||
Delete(ctx context.Context, resourceGroupName string, VMName string) (result compute.VirtualMachinesDeleteFuture, err error)
|
||||
Generalize(ctx context.Context, resourceGroupName string, VMName string) (result autorest.Response, err error)
|
||||
Get(ctx context.Context, resourceGroupName string, VMName string, expand compute.InstanceViewTypes) (result compute.VirtualMachine, err error)
|
||||
InstanceView(ctx context.Context, resourceGroupName string, VMName string) (result compute.VirtualMachineInstanceView, err error)
|
||||
List(ctx context.Context, resourceGroupName string) (result compute.VirtualMachineListResultPage, err error)
|
||||
ListAll(ctx context.Context) (result compute.VirtualMachineListResultPage, err error)
|
||||
ListAvailableSizes(ctx context.Context, resourceGroupName string, VMName string) (result compute.VirtualMachineSizeListResult, err error)
|
||||
ListByLocation(ctx context.Context, location string) (result compute.VirtualMachineListResultPage, err error)
|
||||
PerformMaintenance(ctx context.Context, resourceGroupName string, VMName string) (result compute.VirtualMachinesPerformMaintenanceFuture, err error)
|
||||
PowerOff(ctx context.Context, resourceGroupName string, VMName string, skipShutdown *bool) (result compute.VirtualMachinesPowerOffFuture, err error)
|
||||
Redeploy(ctx context.Context, resourceGroupName string, VMName string) (result compute.VirtualMachinesRedeployFuture, err error)
|
||||
Reimage(ctx context.Context, resourceGroupName string, VMName string, parameters *compute.VirtualMachineReimageParameters) (result compute.VirtualMachinesReimageFuture, err error)
|
||||
Restart(ctx context.Context, resourceGroupName string, VMName string) (result compute.VirtualMachinesRestartFuture, err error)
|
||||
RunCommand(ctx context.Context, resourceGroupName string, VMName string, parameters compute.RunCommandInput) (result compute.VirtualMachinesRunCommandFuture, err error)
|
||||
Start(ctx context.Context, resourceGroupName string, VMName string) (result compute.VirtualMachinesStartFuture, err error)
|
||||
Update(ctx context.Context, resourceGroupName string, VMName string, parameters compute.VirtualMachineUpdate) (result compute.VirtualMachinesUpdateFuture, err error)
|
||||
}
|
||||
|
||||
var _ VirtualMachinesClientAPI = (*compute.VirtualMachinesClient)(nil)
|
||||
|
||||
// VirtualMachineSizesClientAPI contains the set of methods on the VirtualMachineSizesClient type.
|
||||
type VirtualMachineSizesClientAPI interface {
|
||||
List(ctx context.Context, location string) (result compute.VirtualMachineSizeListResult, err error)
|
||||
}
|
||||
|
||||
var _ VirtualMachineSizesClientAPI = (*compute.VirtualMachineSizesClient)(nil)
|
||||
|
||||
// ImagesClientAPI contains the set of methods on the ImagesClient type.
|
||||
type ImagesClientAPI interface {
|
||||
CreateOrUpdate(ctx context.Context, resourceGroupName string, imageName string, parameters compute.Image) (result compute.ImagesCreateOrUpdateFuture, err error)
|
||||
Delete(ctx context.Context, resourceGroupName string, imageName string) (result compute.ImagesDeleteFuture, err error)
|
||||
Get(ctx context.Context, resourceGroupName string, imageName string, expand string) (result compute.Image, err error)
|
||||
List(ctx context.Context) (result compute.ImageListResultPage, err error)
|
||||
ListByResourceGroup(ctx context.Context, resourceGroupName string) (result compute.ImageListResultPage, err error)
|
||||
Update(ctx context.Context, resourceGroupName string, imageName string, parameters compute.ImageUpdate) (result compute.ImagesUpdateFuture, err error)
|
||||
}
|
||||
|
||||
var _ ImagesClientAPI = (*compute.ImagesClient)(nil)
|
||||
|
||||
// VirtualMachineScaleSetsClientAPI contains the set of methods on the VirtualMachineScaleSetsClient type.
|
||||
type VirtualMachineScaleSetsClientAPI interface {
|
||||
ConvertToSinglePlacementGroup(ctx context.Context, resourceGroupName string, VMScaleSetName string, parameters compute.VMScaleSetConvertToSinglePlacementGroupInput) (result autorest.Response, err error)
|
||||
CreateOrUpdate(ctx context.Context, resourceGroupName string, VMScaleSetName string, parameters compute.VirtualMachineScaleSet) (result compute.VirtualMachineScaleSetsCreateOrUpdateFuture, err error)
|
||||
Deallocate(ctx context.Context, resourceGroupName string, VMScaleSetName string, VMInstanceIDs *compute.VirtualMachineScaleSetVMInstanceIDs) (result compute.VirtualMachineScaleSetsDeallocateFuture, err error)
|
||||
Delete(ctx context.Context, resourceGroupName string, VMScaleSetName string) (result compute.VirtualMachineScaleSetsDeleteFuture, err error)
|
||||
DeleteInstances(ctx context.Context, resourceGroupName string, VMScaleSetName string, VMInstanceIDs compute.VirtualMachineScaleSetVMInstanceRequiredIDs) (result compute.VirtualMachineScaleSetsDeleteInstancesFuture, err error)
|
||||
ForceRecoveryServiceFabricPlatformUpdateDomainWalk(ctx context.Context, resourceGroupName string, VMScaleSetName string, platformUpdateDomain int32) (result compute.RecoveryWalkResponse, err error)
|
||||
Get(ctx context.Context, resourceGroupName string, VMScaleSetName string) (result compute.VirtualMachineScaleSet, err error)
|
||||
GetInstanceView(ctx context.Context, resourceGroupName string, VMScaleSetName string) (result compute.VirtualMachineScaleSetInstanceView, err error)
|
||||
GetOSUpgradeHistory(ctx context.Context, resourceGroupName string, VMScaleSetName string) (result compute.VirtualMachineScaleSetListOSUpgradeHistoryPage, err error)
|
||||
List(ctx context.Context, resourceGroupName string) (result compute.VirtualMachineScaleSetListResultPage, err error)
|
||||
ListAll(ctx context.Context) (result compute.VirtualMachineScaleSetListWithLinkResultPage, err error)
|
||||
ListSkus(ctx context.Context, resourceGroupName string, VMScaleSetName string) (result compute.VirtualMachineScaleSetListSkusResultPage, err error)
|
||||
PerformMaintenance(ctx context.Context, resourceGroupName string, VMScaleSetName string, VMInstanceIDs *compute.VirtualMachineScaleSetVMInstanceIDs) (result compute.VirtualMachineScaleSetsPerformMaintenanceFuture, err error)
|
||||
PowerOff(ctx context.Context, resourceGroupName string, VMScaleSetName string, VMInstanceIDs *compute.VirtualMachineScaleSetVMInstanceIDs, skipShutdown *bool) (result compute.VirtualMachineScaleSetsPowerOffFuture, err error)
|
||||
Redeploy(ctx context.Context, resourceGroupName string, VMScaleSetName string, VMInstanceIDs *compute.VirtualMachineScaleSetVMInstanceIDs) (result compute.VirtualMachineScaleSetsRedeployFuture, err error)
|
||||
Reimage(ctx context.Context, resourceGroupName string, VMScaleSetName string, VMScaleSetReimageInput *compute.VirtualMachineScaleSetReimageParameters) (result compute.VirtualMachineScaleSetsReimageFuture, err error)
|
||||
ReimageAll(ctx context.Context, resourceGroupName string, VMScaleSetName string, VMInstanceIDs *compute.VirtualMachineScaleSetVMInstanceIDs) (result compute.VirtualMachineScaleSetsReimageAllFuture, err error)
|
||||
Restart(ctx context.Context, resourceGroupName string, VMScaleSetName string, VMInstanceIDs *compute.VirtualMachineScaleSetVMInstanceIDs) (result compute.VirtualMachineScaleSetsRestartFuture, err error)
|
||||
Start(ctx context.Context, resourceGroupName string, VMScaleSetName string, VMInstanceIDs *compute.VirtualMachineScaleSetVMInstanceIDs) (result compute.VirtualMachineScaleSetsStartFuture, err error)
|
||||
Update(ctx context.Context, resourceGroupName string, VMScaleSetName string, parameters compute.VirtualMachineScaleSetUpdate) (result compute.VirtualMachineScaleSetsUpdateFuture, err error)
|
||||
UpdateInstances(ctx context.Context, resourceGroupName string, VMScaleSetName string, VMInstanceIDs compute.VirtualMachineScaleSetVMInstanceRequiredIDs) (result compute.VirtualMachineScaleSetsUpdateInstancesFuture, err error)
|
||||
}
|
||||
|
||||
var _ VirtualMachineScaleSetsClientAPI = (*compute.VirtualMachineScaleSetsClient)(nil)
|
||||
|
||||
// VirtualMachineScaleSetExtensionsClientAPI contains the set of methods on the VirtualMachineScaleSetExtensionsClient type.
|
||||
type VirtualMachineScaleSetExtensionsClientAPI interface {
|
||||
CreateOrUpdate(ctx context.Context, resourceGroupName string, VMScaleSetName string, vmssExtensionName string, extensionParameters compute.VirtualMachineScaleSetExtension) (result compute.VirtualMachineScaleSetExtensionsCreateOrUpdateFuture, err error)
|
||||
Delete(ctx context.Context, resourceGroupName string, VMScaleSetName string, vmssExtensionName string) (result compute.VirtualMachineScaleSetExtensionsDeleteFuture, err error)
|
||||
Get(ctx context.Context, resourceGroupName string, VMScaleSetName string, vmssExtensionName string, expand string) (result compute.VirtualMachineScaleSetExtension, err error)
|
||||
List(ctx context.Context, resourceGroupName string, VMScaleSetName string) (result compute.VirtualMachineScaleSetExtensionListResultPage, err error)
|
||||
}
|
||||
|
||||
var _ VirtualMachineScaleSetExtensionsClientAPI = (*compute.VirtualMachineScaleSetExtensionsClient)(nil)
|
||||
|
||||
// VirtualMachineScaleSetRollingUpgradesClientAPI contains the set of methods on the VirtualMachineScaleSetRollingUpgradesClient type.
|
||||
type VirtualMachineScaleSetRollingUpgradesClientAPI interface {
|
||||
Cancel(ctx context.Context, resourceGroupName string, VMScaleSetName string) (result compute.VirtualMachineScaleSetRollingUpgradesCancelFuture, err error)
|
||||
GetLatest(ctx context.Context, resourceGroupName string, VMScaleSetName string) (result compute.RollingUpgradeStatusInfo, err error)
|
||||
StartExtensionUpgrade(ctx context.Context, resourceGroupName string, VMScaleSetName string) (result compute.VirtualMachineScaleSetRollingUpgradesStartExtensionUpgradeFuture, err error)
|
||||
StartOSUpgrade(ctx context.Context, resourceGroupName string, VMScaleSetName string) (result compute.VirtualMachineScaleSetRollingUpgradesStartOSUpgradeFuture, err error)
|
||||
}
|
||||
|
||||
var _ VirtualMachineScaleSetRollingUpgradesClientAPI = (*compute.VirtualMachineScaleSetRollingUpgradesClient)(nil)
|
||||
|
||||
// VirtualMachineScaleSetVMsClientAPI contains the set of methods on the VirtualMachineScaleSetVMsClient type.
|
||||
type VirtualMachineScaleSetVMsClientAPI interface {
|
||||
Deallocate(ctx context.Context, resourceGroupName string, VMScaleSetName string, instanceID string) (result compute.VirtualMachineScaleSetVMsDeallocateFuture, err error)
|
||||
Delete(ctx context.Context, resourceGroupName string, VMScaleSetName string, instanceID string) (result compute.VirtualMachineScaleSetVMsDeleteFuture, err error)
|
||||
Get(ctx context.Context, resourceGroupName string, VMScaleSetName string, instanceID string) (result compute.VirtualMachineScaleSetVM, err error)
|
||||
GetInstanceView(ctx context.Context, resourceGroupName string, VMScaleSetName string, instanceID string) (result compute.VirtualMachineScaleSetVMInstanceView, err error)
|
||||
List(ctx context.Context, resourceGroupName string, virtualMachineScaleSetName string, filter string, selectParameter string, expand string) (result compute.VirtualMachineScaleSetVMListResultPage, err error)
|
||||
PerformMaintenance(ctx context.Context, resourceGroupName string, VMScaleSetName string, instanceID string) (result compute.VirtualMachineScaleSetVMsPerformMaintenanceFuture, err error)
|
||||
PowerOff(ctx context.Context, resourceGroupName string, VMScaleSetName string, instanceID string, skipShutdown *bool) (result compute.VirtualMachineScaleSetVMsPowerOffFuture, err error)
|
||||
Redeploy(ctx context.Context, resourceGroupName string, VMScaleSetName string, instanceID string) (result compute.VirtualMachineScaleSetVMsRedeployFuture, err error)
|
||||
Reimage(ctx context.Context, resourceGroupName string, VMScaleSetName string, instanceID string, VMScaleSetVMReimageInput *compute.VirtualMachineScaleSetVMReimageParameters) (result compute.VirtualMachineScaleSetVMsReimageFuture, err error)
|
||||
ReimageAll(ctx context.Context, resourceGroupName string, VMScaleSetName string, instanceID string) (result compute.VirtualMachineScaleSetVMsReimageAllFuture, err error)
|
||||
Restart(ctx context.Context, resourceGroupName string, VMScaleSetName string, instanceID string) (result compute.VirtualMachineScaleSetVMsRestartFuture, err error)
|
||||
RunCommand(ctx context.Context, resourceGroupName string, VMScaleSetName string, instanceID string, parameters compute.RunCommandInput) (result compute.VirtualMachineScaleSetVMsRunCommandFuture, err error)
|
||||
Start(ctx context.Context, resourceGroupName string, VMScaleSetName string, instanceID string) (result compute.VirtualMachineScaleSetVMsStartFuture, err error)
|
||||
Update(ctx context.Context, resourceGroupName string, VMScaleSetName string, instanceID string, parameters compute.VirtualMachineScaleSetVM) (result compute.VirtualMachineScaleSetVMsUpdateFuture, err error)
|
||||
}
|
||||
|
||||
var _ VirtualMachineScaleSetVMsClientAPI = (*compute.VirtualMachineScaleSetVMsClient)(nil)
|
||||
|
||||
// LogAnalyticsClientAPI contains the set of methods on the LogAnalyticsClient type.
|
||||
type LogAnalyticsClientAPI interface {
|
||||
ExportRequestRateByInterval(ctx context.Context, parameters compute.RequestRateByIntervalInput, location string) (result compute.LogAnalyticsExportRequestRateByIntervalFuture, err error)
|
||||
ExportThrottledRequests(ctx context.Context, parameters compute.ThrottledRequestsInput, location string) (result compute.LogAnalyticsExportThrottledRequestsFuture, err error)
|
||||
}
|
||||
|
||||
var _ LogAnalyticsClientAPI = (*compute.LogAnalyticsClient)(nil)
|
||||
|
||||
// VirtualMachineRunCommandsClientAPI contains the set of methods on the VirtualMachineRunCommandsClient type.
|
||||
type VirtualMachineRunCommandsClientAPI interface {
|
||||
Get(ctx context.Context, location string, commandID string) (result compute.RunCommandDocument, err error)
|
||||
List(ctx context.Context, location string) (result compute.RunCommandListResultPage, err error)
|
||||
}
|
||||
|
||||
var _ VirtualMachineRunCommandsClientAPI = (*compute.VirtualMachineRunCommandsClient)(nil)
|
||||
|
||||
// ResourceSkusClientAPI contains the set of methods on the ResourceSkusClient type.
|
||||
type ResourceSkusClientAPI interface {
|
||||
List(ctx context.Context) (result compute.ResourceSkusResultPage, err error)
|
||||
}
|
||||
|
||||
var _ ResourceSkusClientAPI = (*compute.ResourceSkusClient)(nil)
|
||||
|
||||
// DisksClientAPI contains the set of methods on the DisksClient type.
|
||||
type DisksClientAPI interface {
|
||||
CreateOrUpdate(ctx context.Context, resourceGroupName string, diskName string, disk compute.Disk) (result compute.DisksCreateOrUpdateFuture, err error)
|
||||
Delete(ctx context.Context, resourceGroupName string, diskName string) (result compute.DisksDeleteFuture, err error)
|
||||
Get(ctx context.Context, resourceGroupName string, diskName string) (result compute.Disk, err error)
|
||||
GrantAccess(ctx context.Context, resourceGroupName string, diskName string, grantAccessData compute.GrantAccessData) (result compute.DisksGrantAccessFuture, err error)
|
||||
List(ctx context.Context) (result compute.DiskListPage, err error)
|
||||
ListByResourceGroup(ctx context.Context, resourceGroupName string) (result compute.DiskListPage, err error)
|
||||
RevokeAccess(ctx context.Context, resourceGroupName string, diskName string) (result compute.DisksRevokeAccessFuture, err error)
|
||||
Update(ctx context.Context, resourceGroupName string, diskName string, disk compute.DiskUpdate) (result compute.DisksUpdateFuture, err error)
|
||||
}
|
||||
|
||||
var _ DisksClientAPI = (*compute.DisksClient)(nil)
|
||||
|
||||
// SnapshotsClientAPI contains the set of methods on the SnapshotsClient type.
|
||||
type SnapshotsClientAPI interface {
|
||||
CreateOrUpdate(ctx context.Context, resourceGroupName string, snapshotName string, snapshot compute.Snapshot) (result compute.SnapshotsCreateOrUpdateFuture, err error)
|
||||
Delete(ctx context.Context, resourceGroupName string, snapshotName string) (result compute.SnapshotsDeleteFuture, err error)
|
||||
Get(ctx context.Context, resourceGroupName string, snapshotName string) (result compute.Snapshot, err error)
|
||||
GrantAccess(ctx context.Context, resourceGroupName string, snapshotName string, grantAccessData compute.GrantAccessData) (result compute.SnapshotsGrantAccessFuture, err error)
|
||||
List(ctx context.Context) (result compute.SnapshotListPage, err error)
|
||||
ListByResourceGroup(ctx context.Context, resourceGroupName string) (result compute.SnapshotListPage, err error)
|
||||
RevokeAccess(ctx context.Context, resourceGroupName string, snapshotName string) (result compute.SnapshotsRevokeAccessFuture, err error)
|
||||
Update(ctx context.Context, resourceGroupName string, snapshotName string, snapshot compute.SnapshotUpdate) (result compute.SnapshotsUpdateFuture, err error)
|
||||
}
|
||||
|
||||
var _ SnapshotsClientAPI = (*compute.SnapshotsClient)(nil)
|
||||
|
||||
// GalleriesClientAPI contains the set of methods on the GalleriesClient type.
|
||||
type GalleriesClientAPI interface {
|
||||
CreateOrUpdate(ctx context.Context, resourceGroupName string, galleryName string, gallery compute.Gallery) (result compute.GalleriesCreateOrUpdateFuture, err error)
|
||||
Delete(ctx context.Context, resourceGroupName string, galleryName string) (result compute.GalleriesDeleteFuture, err error)
|
||||
Get(ctx context.Context, resourceGroupName string, galleryName string) (result compute.Gallery, err error)
|
||||
List(ctx context.Context) (result compute.GalleryListPage, err error)
|
||||
ListByResourceGroup(ctx context.Context, resourceGroupName string) (result compute.GalleryListPage, err error)
|
||||
}
|
||||
|
||||
var _ GalleriesClientAPI = (*compute.GalleriesClient)(nil)
|
||||
|
||||
// GalleryImagesClientAPI contains the set of methods on the GalleryImagesClient type.
|
||||
type GalleryImagesClientAPI interface {
|
||||
CreateOrUpdate(ctx context.Context, resourceGroupName string, galleryName string, galleryImageName string, galleryImage compute.GalleryImage) (result compute.GalleryImagesCreateOrUpdateFuture, err error)
|
||||
Delete(ctx context.Context, resourceGroupName string, galleryName string, galleryImageName string) (result compute.GalleryImagesDeleteFuture, err error)
|
||||
Get(ctx context.Context, resourceGroupName string, galleryName string, galleryImageName string) (result compute.GalleryImage, err error)
|
||||
ListByGallery(ctx context.Context, resourceGroupName string, galleryName string) (result compute.GalleryImageListPage, err error)
|
||||
}
|
||||
|
||||
var _ GalleryImagesClientAPI = (*compute.GalleryImagesClient)(nil)
|
||||
|
||||
// GalleryImageVersionsClientAPI contains the set of methods on the GalleryImageVersionsClient type.
|
||||
type GalleryImageVersionsClientAPI interface {
|
||||
CreateOrUpdate(ctx context.Context, resourceGroupName string, galleryName string, galleryImageName string, galleryImageVersionName string, galleryImageVersion compute.GalleryImageVersion) (result compute.GalleryImageVersionsCreateOrUpdateFuture, err error)
|
||||
Delete(ctx context.Context, resourceGroupName string, galleryName string, galleryImageName string, galleryImageVersionName string) (result compute.GalleryImageVersionsDeleteFuture, err error)
|
||||
Get(ctx context.Context, resourceGroupName string, galleryName string, galleryImageName string, galleryImageVersionName string, expand compute.ReplicationStatusTypes) (result compute.GalleryImageVersion, err error)
|
||||
ListByGalleryImage(ctx context.Context, resourceGroupName string, galleryName string, galleryImageName string) (result compute.GalleryImageVersionListPage, err error)
|
||||
}
|
||||
|
||||
var _ GalleryImageVersionsClientAPI = (*compute.GalleryImageVersionsClient)(nil)
|
||||
|
||||
// ContainerServicesClientAPI contains the set of methods on the ContainerServicesClient type.
|
||||
type ContainerServicesClientAPI interface {
|
||||
CreateOrUpdate(ctx context.Context, resourceGroupName string, containerServiceName string, parameters compute.ContainerService) (result compute.ContainerServicesCreateOrUpdateFuture, err error)
|
||||
Delete(ctx context.Context, resourceGroupName string, containerServiceName string) (result compute.ContainerServicesDeleteFuture, err error)
|
||||
Get(ctx context.Context, resourceGroupName string, containerServiceName string) (result compute.ContainerService, err error)
|
||||
List(ctx context.Context) (result compute.ContainerServiceListResultPage, err error)
|
||||
ListByResourceGroup(ctx context.Context, resourceGroupName string) (result compute.ContainerServiceListResultPage, err error)
|
||||
}
|
||||
|
||||
var _ ContainerServicesClientAPI = (*compute.ContainerServicesClient)(nil)
|
|
@ -0,0 +1,712 @@
|
|||
package auth
|
||||
|
||||
// Copyright 2017 Microsoft Corporation
|
||||
//
|
||||
// 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.
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"unicode/utf16"
|
||||
|
||||
"github.com/Azure/go-autorest/autorest"
|
||||
"github.com/Azure/go-autorest/autorest/adal"
|
||||
"github.com/Azure/go-autorest/autorest/azure"
|
||||
"github.com/Azure/go-autorest/autorest/azure/cli"
|
||||
"github.com/dimchansky/utfbom"
|
||||
"golang.org/x/crypto/pkcs12"
|
||||
)
|
||||
|
||||
// The possible keys in the Values map.
|
||||
const (
|
||||
SubscriptionID = "AZURE_SUBSCRIPTION_ID"
|
||||
TenantID = "AZURE_TENANT_ID"
|
||||
ClientID = "AZURE_CLIENT_ID"
|
||||
ClientSecret = "AZURE_CLIENT_SECRET"
|
||||
CertificatePath = "AZURE_CERTIFICATE_PATH"
|
||||
CertificatePassword = "AZURE_CERTIFICATE_PASSWORD"
|
||||
Username = "AZURE_USERNAME"
|
||||
Password = "AZURE_PASSWORD"
|
||||
EnvironmentName = "AZURE_ENVIRONMENT"
|
||||
Resource = "AZURE_AD_RESOURCE"
|
||||
ActiveDirectoryEndpoint = "ActiveDirectoryEndpoint"
|
||||
ResourceManagerEndpoint = "ResourceManagerEndpoint"
|
||||
GraphResourceID = "GraphResourceID"
|
||||
SQLManagementEndpoint = "SQLManagementEndpoint"
|
||||
GalleryEndpoint = "GalleryEndpoint"
|
||||
ManagementEndpoint = "ManagementEndpoint"
|
||||
)
|
||||
|
||||
// NewAuthorizerFromEnvironment creates an Authorizer configured from environment variables in the order:
|
||||
// 1. Client credentials
|
||||
// 2. Client certificate
|
||||
// 3. Username password
|
||||
// 4. MSI
|
||||
func NewAuthorizerFromEnvironment() (autorest.Authorizer, error) {
|
||||
settings, err := GetSettingsFromEnvironment()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return settings.GetAuthorizer()
|
||||
}
|
||||
|
||||
// NewAuthorizerFromEnvironmentWithResource creates an Authorizer configured from environment variables in the order:
|
||||
// 1. Client credentials
|
||||
// 2. Client certificate
|
||||
// 3. Username password
|
||||
// 4. MSI
|
||||
func NewAuthorizerFromEnvironmentWithResource(resource string) (autorest.Authorizer, error) {
|
||||
settings, err := GetSettingsFromEnvironment()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
settings.Values[Resource] = resource
|
||||
return settings.GetAuthorizer()
|
||||
}
|
||||
|
||||
// EnvironmentSettings contains the available authentication settings.
|
||||
type EnvironmentSettings struct {
|
||||
Values map[string]string
|
||||
Environment azure.Environment
|
||||
}
|
||||
|
||||
// GetSettingsFromEnvironment returns the available authentication settings from the environment.
|
||||
func GetSettingsFromEnvironment() (s EnvironmentSettings, err error) {
|
||||
s = EnvironmentSettings{
|
||||
Values: map[string]string{},
|
||||
}
|
||||
s.setValue(SubscriptionID)
|
||||
s.setValue(TenantID)
|
||||
s.setValue(ClientID)
|
||||
s.setValue(ClientSecret)
|
||||
s.setValue(CertificatePath)
|
||||
s.setValue(CertificatePassword)
|
||||
s.setValue(Username)
|
||||
s.setValue(Password)
|
||||
s.setValue(EnvironmentName)
|
||||
s.setValue(Resource)
|
||||
if v := s.Values[EnvironmentName]; v == "" {
|
||||
s.Environment = azure.PublicCloud
|
||||
} else {
|
||||
s.Environment, err = azure.EnvironmentFromName(v)
|
||||
}
|
||||
if s.Values[Resource] == "" {
|
||||
s.Values[Resource] = s.Environment.ResourceManagerEndpoint
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GetSubscriptionID returns the available subscription ID or an empty string.
|
||||
func (settings EnvironmentSettings) GetSubscriptionID() string {
|
||||
return settings.Values[SubscriptionID]
|
||||
}
|
||||
|
||||
// adds the specified environment variable value to the Values map if it exists
|
||||
func (settings EnvironmentSettings) setValue(key string) {
|
||||
if v := os.Getenv(key); v != "" {
|
||||
settings.Values[key] = v
|
||||
}
|
||||
}
|
||||
|
||||
// helper to return client and tenant IDs
|
||||
func (settings EnvironmentSettings) getClientAndTenant() (string, string) {
|
||||
clientID := settings.Values[ClientID]
|
||||
tenantID := settings.Values[TenantID]
|
||||
return clientID, tenantID
|
||||
}
|
||||
|
||||
// GetClientCredentials creates a config object from the available client credentials.
|
||||
// An error is returned if no client credentials are available.
|
||||
func (settings EnvironmentSettings) GetClientCredentials() (ClientCredentialsConfig, error) {
|
||||
secret := settings.Values[ClientSecret]
|
||||
if secret == "" {
|
||||
return ClientCredentialsConfig{}, errors.New("missing client secret")
|
||||
}
|
||||
clientID, tenantID := settings.getClientAndTenant()
|
||||
config := NewClientCredentialsConfig(clientID, secret, tenantID)
|
||||
config.AADEndpoint = settings.Environment.ActiveDirectoryEndpoint
|
||||
config.Resource = settings.Values[Resource]
|
||||
return config, nil
|
||||
}
|
||||
|
||||
// GetClientCertificate creates a config object from the available certificate credentials.
|
||||
// An error is returned if no certificate credentials are available.
|
||||
func (settings EnvironmentSettings) GetClientCertificate() (ClientCertificateConfig, error) {
|
||||
certPath := settings.Values[CertificatePath]
|
||||
if certPath == "" {
|
||||
return ClientCertificateConfig{}, errors.New("missing certificate path")
|
||||
}
|
||||
certPwd := settings.Values[CertificatePassword]
|
||||
clientID, tenantID := settings.getClientAndTenant()
|
||||
config := NewClientCertificateConfig(certPath, certPwd, clientID, tenantID)
|
||||
config.AADEndpoint = settings.Environment.ActiveDirectoryEndpoint
|
||||
config.Resource = settings.Values[Resource]
|
||||
return config, nil
|
||||
}
|
||||
|
||||
// GetUsernamePassword creates a config object from the available username/password credentials.
|
||||
// An error is returned if no username/password credentials are available.
|
||||
func (settings EnvironmentSettings) GetUsernamePassword() (UsernamePasswordConfig, error) {
|
||||
username := settings.Values[Username]
|
||||
password := settings.Values[Password]
|
||||
if username == "" || password == "" {
|
||||
return UsernamePasswordConfig{}, errors.New("missing username/password")
|
||||
}
|
||||
clientID, tenantID := settings.getClientAndTenant()
|
||||
config := NewUsernamePasswordConfig(username, password, clientID, tenantID)
|
||||
config.AADEndpoint = settings.Environment.ActiveDirectoryEndpoint
|
||||
config.Resource = settings.Values[Resource]
|
||||
return config, nil
|
||||
}
|
||||
|
||||
// GetMSI creates a MSI config object from the available client ID.
|
||||
func (settings EnvironmentSettings) GetMSI() MSIConfig {
|
||||
config := NewMSIConfig()
|
||||
config.Resource = settings.Values[Resource]
|
||||
config.ClientID = settings.Values[ClientID]
|
||||
return config
|
||||
}
|
||||
|
||||
// GetDeviceFlow creates a device-flow config object from the available client and tenant IDs.
|
||||
func (settings EnvironmentSettings) GetDeviceFlow() DeviceFlowConfig {
|
||||
clientID, tenantID := settings.getClientAndTenant()
|
||||
config := NewDeviceFlowConfig(clientID, tenantID)
|
||||
config.AADEndpoint = settings.Environment.ActiveDirectoryEndpoint
|
||||
config.Resource = settings.Values[Resource]
|
||||
return config
|
||||
}
|
||||
|
||||
// GetAuthorizer creates an Authorizer configured from environment variables in the order:
|
||||
// 1. Client credentials
|
||||
// 2. Client certificate
|
||||
// 3. Username password
|
||||
// 4. MSI
|
||||
func (settings EnvironmentSettings) GetAuthorizer() (autorest.Authorizer, error) {
|
||||
//1.Client Credentials
|
||||
if c, e := settings.GetClientCredentials(); e == nil {
|
||||
return c.Authorizer()
|
||||
}
|
||||
|
||||
//2. Client Certificate
|
||||
if c, e := settings.GetClientCertificate(); e == nil {
|
||||
return c.Authorizer()
|
||||
}
|
||||
|
||||
//3. Username Password
|
||||
if c, e := settings.GetUsernamePassword(); e == nil {
|
||||
return c.Authorizer()
|
||||
}
|
||||
|
||||
// 4. MSI
|
||||
return settings.GetMSI().Authorizer()
|
||||
}
|
||||
|
||||
// NewAuthorizerFromFile creates an Authorizer configured from a configuration file in the following order.
|
||||
// 1. Client credentials
|
||||
// 2. Client certificate
|
||||
func NewAuthorizerFromFile(baseURI string) (autorest.Authorizer, error) {
|
||||
settings, err := GetSettingsFromFile()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if a, err := settings.ClientCredentialsAuthorizer(baseURI); err == nil {
|
||||
return a, err
|
||||
}
|
||||
if a, err := settings.ClientCertificateAuthorizer(baseURI); err == nil {
|
||||
return a, err
|
||||
}
|
||||
return nil, errors.New("auth file missing client and certificate credentials")
|
||||
}
|
||||
|
||||
// NewAuthorizerFromFileWithResource creates an Authorizer configured from a configuration file in the following order.
|
||||
// 1. Client credentials
|
||||
// 2. Client certificate
|
||||
func NewAuthorizerFromFileWithResource(resource string) (autorest.Authorizer, error) {
|
||||
s, err := GetSettingsFromFile()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if a, err := s.ClientCredentialsAuthorizerWithResource(resource); err == nil {
|
||||
return a, err
|
||||
}
|
||||
if a, err := s.ClientCertificateAuthorizerWithResource(resource); err == nil {
|
||||
return a, err
|
||||
}
|
||||
return nil, errors.New("auth file missing client and certificate credentials")
|
||||
}
|
||||
|
||||
// NewAuthorizerFromCLI creates an Authorizer configured from Azure CLI 2.0 for local development scenarios.
|
||||
func NewAuthorizerFromCLI() (autorest.Authorizer, error) {
|
||||
settings, err := GetSettingsFromEnvironment()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if settings.Values[Resource] == "" {
|
||||
settings.Values[Resource] = settings.Environment.ResourceManagerEndpoint
|
||||
}
|
||||
|
||||
return NewAuthorizerFromCLIWithResource(settings.Values[Resource])
|
||||
}
|
||||
|
||||
// NewAuthorizerFromCLIWithResource creates an Authorizer configured from Azure CLI 2.0 for local development scenarios.
|
||||
func NewAuthorizerFromCLIWithResource(resource string) (autorest.Authorizer, error) {
|
||||
token, err := cli.GetTokenFromCLI(resource)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
adalToken, err := token.ToADALToken()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return autorest.NewBearerAuthorizer(&adalToken), nil
|
||||
}
|
||||
|
||||
// GetSettingsFromFile returns the available authentication settings from an Azure CLI authentication file.
|
||||
func GetSettingsFromFile() (FileSettings, error) {
|
||||
s := FileSettings{}
|
||||
fileLocation := os.Getenv("AZURE_AUTH_LOCATION")
|
||||
if fileLocation == "" {
|
||||
return s, errors.New("environment variable AZURE_AUTH_LOCATION is not set")
|
||||
}
|
||||
|
||||
contents, err := ioutil.ReadFile(fileLocation)
|
||||
if err != nil {
|
||||
return s, err
|
||||
}
|
||||
|
||||
// Auth file might be encoded
|
||||
decoded, err := decode(contents)
|
||||
if err != nil {
|
||||
return s, err
|
||||
}
|
||||
|
||||
authFile := map[string]interface{}{}
|
||||
err = json.Unmarshal(decoded, &authFile)
|
||||
if err != nil {
|
||||
return s, err
|
||||
}
|
||||
|
||||
s.Values = map[string]string{}
|
||||
s.setKeyValue(ClientID, authFile["clientId"])
|
||||
s.setKeyValue(ClientSecret, authFile["clientSecret"])
|
||||
s.setKeyValue(CertificatePath, authFile["clientCertificate"])
|
||||
s.setKeyValue(CertificatePassword, authFile["clientCertificatePassword"])
|
||||
s.setKeyValue(SubscriptionID, authFile["subscriptionId"])
|
||||
s.setKeyValue(TenantID, authFile["tenantId"])
|
||||
s.setKeyValue(ActiveDirectoryEndpoint, authFile["activeDirectoryEndpointUrl"])
|
||||
s.setKeyValue(ResourceManagerEndpoint, authFile["resourceManagerEndpointUrl"])
|
||||
s.setKeyValue(GraphResourceID, authFile["activeDirectoryGraphResourceId"])
|
||||
s.setKeyValue(SQLManagementEndpoint, authFile["sqlManagementEndpointUrl"])
|
||||
s.setKeyValue(GalleryEndpoint, authFile["galleryEndpointUrl"])
|
||||
s.setKeyValue(ManagementEndpoint, authFile["managementEndpointUrl"])
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// FileSettings contains the available authentication settings.
|
||||
type FileSettings struct {
|
||||
Values map[string]string
|
||||
}
|
||||
|
||||
// GetSubscriptionID returns the available subscription ID or an empty string.
|
||||
func (settings FileSettings) GetSubscriptionID() string {
|
||||
return settings.Values[SubscriptionID]
|
||||
}
|
||||
|
||||
// adds the specified value to the Values map if it isn't nil
|
||||
func (settings FileSettings) setKeyValue(key string, val interface{}) {
|
||||
if val != nil {
|
||||
settings.Values[key] = val.(string)
|
||||
}
|
||||
}
|
||||
|
||||
// returns the specified AAD endpoint or the public cloud endpoint if unspecified
|
||||
func (settings FileSettings) getAADEndpoint() string {
|
||||
if v, ok := settings.Values[ActiveDirectoryEndpoint]; ok {
|
||||
return v
|
||||
}
|
||||
return azure.PublicCloud.ActiveDirectoryEndpoint
|
||||
}
|
||||
|
||||
// ServicePrincipalTokenFromClientCredentials creates a ServicePrincipalToken from the available client credentials.
|
||||
func (settings FileSettings) ServicePrincipalTokenFromClientCredentials(baseURI string) (*adal.ServicePrincipalToken, error) {
|
||||
resource, err := settings.getResourceForToken(baseURI)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return settings.ServicePrincipalTokenFromClientCredentialsWithResource(resource)
|
||||
}
|
||||
|
||||
// ClientCredentialsAuthorizer creates an authorizer from the available client credentials.
|
||||
func (settings FileSettings) ClientCredentialsAuthorizer(baseURI string) (autorest.Authorizer, error) {
|
||||
resource, err := settings.getResourceForToken(baseURI)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return settings.ClientCredentialsAuthorizerWithResource(resource)
|
||||
}
|
||||
|
||||
// ServicePrincipalTokenFromClientCredentialsWithResource creates a ServicePrincipalToken
|
||||
// from the available client credentials and the specified resource.
|
||||
func (settings FileSettings) ServicePrincipalTokenFromClientCredentialsWithResource(resource string) (*adal.ServicePrincipalToken, error) {
|
||||
if _, ok := settings.Values[ClientSecret]; !ok {
|
||||
return nil, errors.New("missing client secret")
|
||||
}
|
||||
config, err := adal.NewOAuthConfig(settings.getAADEndpoint(), settings.Values[TenantID])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return adal.NewServicePrincipalToken(*config, settings.Values[ClientID], settings.Values[ClientSecret], resource)
|
||||
}
|
||||
|
||||
func (settings FileSettings) clientCertificateConfigWithResource(resource string) (ClientCertificateConfig, error) {
|
||||
if _, ok := settings.Values[CertificatePath]; !ok {
|
||||
return ClientCertificateConfig{}, errors.New("missing certificate path")
|
||||
}
|
||||
cfg := NewClientCertificateConfig(settings.Values[CertificatePath], settings.Values[CertificatePassword], settings.Values[ClientID], settings.Values[TenantID])
|
||||
cfg.AADEndpoint = settings.getAADEndpoint()
|
||||
cfg.Resource = resource
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
// ClientCredentialsAuthorizerWithResource creates an authorizer from the available client credentials and the specified resource.
|
||||
func (settings FileSettings) ClientCredentialsAuthorizerWithResource(resource string) (autorest.Authorizer, error) {
|
||||
spToken, err := settings.ServicePrincipalTokenFromClientCredentialsWithResource(resource)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return autorest.NewBearerAuthorizer(spToken), nil
|
||||
}
|
||||
|
||||
// ServicePrincipalTokenFromClientCertificate creates a ServicePrincipalToken from the available certificate credentials.
|
||||
func (settings FileSettings) ServicePrincipalTokenFromClientCertificate(baseURI string) (*adal.ServicePrincipalToken, error) {
|
||||
resource, err := settings.getResourceForToken(baseURI)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return settings.ServicePrincipalTokenFromClientCertificateWithResource(resource)
|
||||
}
|
||||
|
||||
// ClientCertificateAuthorizer creates an authorizer from the available certificate credentials.
|
||||
func (settings FileSettings) ClientCertificateAuthorizer(baseURI string) (autorest.Authorizer, error) {
|
||||
resource, err := settings.getResourceForToken(baseURI)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return settings.ClientCertificateAuthorizerWithResource(resource)
|
||||
}
|
||||
|
||||
// ServicePrincipalTokenFromClientCertificateWithResource creates a ServicePrincipalToken from the available certificate credentials.
|
||||
func (settings FileSettings) ServicePrincipalTokenFromClientCertificateWithResource(resource string) (*adal.ServicePrincipalToken, error) {
|
||||
cfg, err := settings.clientCertificateConfigWithResource(resource)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cfg.ServicePrincipalToken()
|
||||
}
|
||||
|
||||
// ClientCertificateAuthorizerWithResource creates an authorizer from the available certificate credentials and the specified resource.
|
||||
func (settings FileSettings) ClientCertificateAuthorizerWithResource(resource string) (autorest.Authorizer, error) {
|
||||
cfg, err := settings.clientCertificateConfigWithResource(resource)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cfg.Authorizer()
|
||||
}
|
||||
|
||||
func decode(b []byte) ([]byte, error) {
|
||||
reader, enc := utfbom.Skip(bytes.NewReader(b))
|
||||
|
||||
switch enc {
|
||||
case utfbom.UTF16LittleEndian:
|
||||
u16 := make([]uint16, (len(b)/2)-1)
|
||||
err := binary.Read(reader, binary.LittleEndian, &u16)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return []byte(string(utf16.Decode(u16))), nil
|
||||
case utfbom.UTF16BigEndian:
|
||||
u16 := make([]uint16, (len(b)/2)-1)
|
||||
err := binary.Read(reader, binary.BigEndian, &u16)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return []byte(string(utf16.Decode(u16))), nil
|
||||
}
|
||||
return ioutil.ReadAll(reader)
|
||||
}
|
||||
|
||||
func (settings FileSettings) getResourceForToken(baseURI string) (string, error) {
|
||||
// Compare dafault base URI from the SDK to the endpoints from the public cloud
|
||||
// Base URI and token resource are the same string. This func finds the authentication
|
||||
// file field that matches the SDK base URI. The SDK defines the public cloud
|
||||
// endpoint as its default base URI
|
||||
if !strings.HasSuffix(baseURI, "/") {
|
||||
baseURI += "/"
|
||||
}
|
||||
switch baseURI {
|
||||
case azure.PublicCloud.ServiceManagementEndpoint:
|
||||
return settings.Values[ManagementEndpoint], nil
|
||||
case azure.PublicCloud.ResourceManagerEndpoint:
|
||||
return settings.Values[ResourceManagerEndpoint], nil
|
||||
case azure.PublicCloud.ActiveDirectoryEndpoint:
|
||||
return settings.Values[ActiveDirectoryEndpoint], nil
|
||||
case azure.PublicCloud.GalleryEndpoint:
|
||||
return settings.Values[GalleryEndpoint], nil
|
||||
case azure.PublicCloud.GraphEndpoint:
|
||||
return settings.Values[GraphResourceID], nil
|
||||
}
|
||||
return "", fmt.Errorf("auth: base URI not found in endpoints")
|
||||
}
|
||||
|
||||
// NewClientCredentialsConfig creates an AuthorizerConfig object configured to obtain an Authorizer through Client Credentials.
|
||||
// Defaults to Public Cloud and Resource Manager Endpoint.
|
||||
func NewClientCredentialsConfig(clientID string, clientSecret string, tenantID string) ClientCredentialsConfig {
|
||||
return ClientCredentialsConfig{
|
||||
ClientID: clientID,
|
||||
ClientSecret: clientSecret,
|
||||
TenantID: tenantID,
|
||||
Resource: azure.PublicCloud.ResourceManagerEndpoint,
|
||||
AADEndpoint: azure.PublicCloud.ActiveDirectoryEndpoint,
|
||||
}
|
||||
}
|
||||
|
||||
// NewClientCertificateConfig creates a ClientCertificateConfig object configured to obtain an Authorizer through client certificate.
|
||||
// Defaults to Public Cloud and Resource Manager Endpoint.
|
||||
func NewClientCertificateConfig(certificatePath string, certificatePassword string, clientID string, tenantID string) ClientCertificateConfig {
|
||||
return ClientCertificateConfig{
|
||||
CertificatePath: certificatePath,
|
||||
CertificatePassword: certificatePassword,
|
||||
ClientID: clientID,
|
||||
TenantID: tenantID,
|
||||
Resource: azure.PublicCloud.ResourceManagerEndpoint,
|
||||
AADEndpoint: azure.PublicCloud.ActiveDirectoryEndpoint,
|
||||
}
|
||||
}
|
||||
|
||||
// NewUsernamePasswordConfig creates an UsernamePasswordConfig object configured to obtain an Authorizer through username and password.
|
||||
// Defaults to Public Cloud and Resource Manager Endpoint.
|
||||
func NewUsernamePasswordConfig(username string, password string, clientID string, tenantID string) UsernamePasswordConfig {
|
||||
return UsernamePasswordConfig{
|
||||
Username: username,
|
||||
Password: password,
|
||||
ClientID: clientID,
|
||||
TenantID: tenantID,
|
||||
Resource: azure.PublicCloud.ResourceManagerEndpoint,
|
||||
AADEndpoint: azure.PublicCloud.ActiveDirectoryEndpoint,
|
||||
}
|
||||
}
|
||||
|
||||
// NewMSIConfig creates an MSIConfig object configured to obtain an Authorizer through MSI.
|
||||
func NewMSIConfig() MSIConfig {
|
||||
return MSIConfig{
|
||||
Resource: azure.PublicCloud.ResourceManagerEndpoint,
|
||||
}
|
||||
}
|
||||
|
||||
// NewDeviceFlowConfig creates a DeviceFlowConfig object configured to obtain an Authorizer through device flow.
|
||||
// Defaults to Public Cloud and Resource Manager Endpoint.
|
||||
func NewDeviceFlowConfig(clientID string, tenantID string) DeviceFlowConfig {
|
||||
return DeviceFlowConfig{
|
||||
ClientID: clientID,
|
||||
TenantID: tenantID,
|
||||
Resource: azure.PublicCloud.ResourceManagerEndpoint,
|
||||
AADEndpoint: azure.PublicCloud.ActiveDirectoryEndpoint,
|
||||
}
|
||||
}
|
||||
|
||||
//AuthorizerConfig provides an authorizer from the configuration provided.
|
||||
type AuthorizerConfig interface {
|
||||
Authorizer() (autorest.Authorizer, error)
|
||||
}
|
||||
|
||||
// ClientCredentialsConfig provides the options to get a bearer authorizer from client credentials.
|
||||
type ClientCredentialsConfig struct {
|
||||
ClientID string
|
||||
ClientSecret string
|
||||
TenantID string
|
||||
AADEndpoint string
|
||||
Resource string
|
||||
}
|
||||
|
||||
// ServicePrincipalToken creates a ServicePrincipalToken from client credentials.
|
||||
func (ccc ClientCredentialsConfig) ServicePrincipalToken() (*adal.ServicePrincipalToken, error) {
|
||||
oauthConfig, err := adal.NewOAuthConfig(ccc.AADEndpoint, ccc.TenantID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return adal.NewServicePrincipalToken(*oauthConfig, ccc.ClientID, ccc.ClientSecret, ccc.Resource)
|
||||
}
|
||||
|
||||
// Authorizer gets the authorizer from client credentials.
|
||||
func (ccc ClientCredentialsConfig) Authorizer() (autorest.Authorizer, error) {
|
||||
spToken, err := ccc.ServicePrincipalToken()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get oauth token from client credentials: %v", err)
|
||||
}
|
||||
return autorest.NewBearerAuthorizer(spToken), nil
|
||||
}
|
||||
|
||||
// ClientCertificateConfig provides the options to get a bearer authorizer from a client certificate.
|
||||
type ClientCertificateConfig struct {
|
||||
ClientID string
|
||||
CertificatePath string
|
||||
CertificatePassword string
|
||||
TenantID string
|
||||
AADEndpoint string
|
||||
Resource string
|
||||
}
|
||||
|
||||
// ServicePrincipalToken creates a ServicePrincipalToken from client certificate.
|
||||
func (ccc ClientCertificateConfig) ServicePrincipalToken() (*adal.ServicePrincipalToken, error) {
|
||||
oauthConfig, err := adal.NewOAuthConfig(ccc.AADEndpoint, ccc.TenantID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
certData, err := ioutil.ReadFile(ccc.CertificatePath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read the certificate file (%s): %v", ccc.CertificatePath, err)
|
||||
}
|
||||
certificate, rsaPrivateKey, err := decodePkcs12(certData, ccc.CertificatePassword)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode pkcs12 certificate while creating spt: %v", err)
|
||||
}
|
||||
return adal.NewServicePrincipalTokenFromCertificate(*oauthConfig, ccc.ClientID, certificate, rsaPrivateKey, ccc.Resource)
|
||||
}
|
||||
|
||||
// Authorizer gets an authorizer object from client certificate.
|
||||
func (ccc ClientCertificateConfig) Authorizer() (autorest.Authorizer, error) {
|
||||
spToken, err := ccc.ServicePrincipalToken()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get oauth token from certificate auth: %v", err)
|
||||
}
|
||||
return autorest.NewBearerAuthorizer(spToken), nil
|
||||
}
|
||||
|
||||
// DeviceFlowConfig provides the options to get a bearer authorizer using device flow authentication.
|
||||
type DeviceFlowConfig struct {
|
||||
ClientID string
|
||||
TenantID string
|
||||
AADEndpoint string
|
||||
Resource string
|
||||
}
|
||||
|
||||
// Authorizer gets the authorizer from device flow.
|
||||
func (dfc DeviceFlowConfig) Authorizer() (autorest.Authorizer, error) {
|
||||
spToken, err := dfc.ServicePrincipalToken()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get oauth token from device flow: %v", err)
|
||||
}
|
||||
return autorest.NewBearerAuthorizer(spToken), nil
|
||||
}
|
||||
|
||||
// ServicePrincipalToken gets the service principal token from device flow.
|
||||
func (dfc DeviceFlowConfig) ServicePrincipalToken() (*adal.ServicePrincipalToken, error) {
|
||||
oauthConfig, err := adal.NewOAuthConfig(dfc.AADEndpoint, dfc.TenantID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
oauthClient := &autorest.Client{}
|
||||
deviceCode, err := adal.InitiateDeviceAuth(oauthClient, *oauthConfig, dfc.ClientID, dfc.Resource)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to start device auth flow: %s", err)
|
||||
}
|
||||
log.Println(*deviceCode.Message)
|
||||
token, err := adal.WaitForUserCompletion(oauthClient, deviceCode)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to finish device auth flow: %s", err)
|
||||
}
|
||||
return adal.NewServicePrincipalTokenFromManualToken(*oauthConfig, dfc.ClientID, dfc.Resource, *token)
|
||||
}
|
||||
|
||||
func decodePkcs12(pkcs []byte, password string) (*x509.Certificate, *rsa.PrivateKey, error) {
|
||||
privateKey, certificate, err := pkcs12.Decode(pkcs, password)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
rsaPrivateKey, isRsaKey := privateKey.(*rsa.PrivateKey)
|
||||
if !isRsaKey {
|
||||
return nil, nil, fmt.Errorf("PKCS#12 certificate must contain an RSA private key")
|
||||
}
|
||||
|
||||
return certificate, rsaPrivateKey, nil
|
||||
}
|
||||
|
||||
// UsernamePasswordConfig provides the options to get a bearer authorizer from a username and a password.
|
||||
type UsernamePasswordConfig struct {
|
||||
ClientID string
|
||||
Username string
|
||||
Password string
|
||||
TenantID string
|
||||
AADEndpoint string
|
||||
Resource string
|
||||
}
|
||||
|
||||
// ServicePrincipalToken creates a ServicePrincipalToken from username and password.
|
||||
func (ups UsernamePasswordConfig) ServicePrincipalToken() (*adal.ServicePrincipalToken, error) {
|
||||
oauthConfig, err := adal.NewOAuthConfig(ups.AADEndpoint, ups.TenantID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return adal.NewServicePrincipalTokenFromUsernamePassword(*oauthConfig, ups.ClientID, ups.Username, ups.Password, ups.Resource)
|
||||
}
|
||||
|
||||
// Authorizer gets the authorizer from a username and a password.
|
||||
func (ups UsernamePasswordConfig) Authorizer() (autorest.Authorizer, error) {
|
||||
spToken, err := ups.ServicePrincipalToken()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get oauth token from username and password auth: %v", err)
|
||||
}
|
||||
return autorest.NewBearerAuthorizer(spToken), nil
|
||||
}
|
||||
|
||||
// MSIConfig provides the options to get a bearer authorizer through MSI.
|
||||
type MSIConfig struct {
|
||||
Resource string
|
||||
ClientID string
|
||||
}
|
||||
|
||||
// Authorizer gets the authorizer from MSI.
|
||||
func (mc MSIConfig) Authorizer() (autorest.Authorizer, error) {
|
||||
msiEndpoint, err := adal.GetMSIVMEndpoint()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var spToken *adal.ServicePrincipalToken
|
||||
if mc.ClientID == "" {
|
||||
spToken, err = adal.NewServicePrincipalTokenFromMSI(msiEndpoint, mc.Resource)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get oauth token from MSI: %v", err)
|
||||
}
|
||||
} else {
|
||||
spToken, err = adal.NewServicePrincipalTokenFromMSIWithUserAssignedID(msiEndpoint, mc.Resource, mc.ClientID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get oauth token from MSI for user assigned identity: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return autorest.NewBearerAuthorizer(spToken), nil
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
package cli
|
||||
|
||||
// Copyright 2017 Microsoft Corporation
|
||||
//
|
||||
// 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.
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/dimchansky/utfbom"
|
||||
"github.com/mitchellh/go-homedir"
|
||||
)
|
||||
|
||||
// Profile represents a Profile from the Azure CLI
|
||||
type Profile struct {
|
||||
InstallationID string `json:"installationId"`
|
||||
Subscriptions []Subscription `json:"subscriptions"`
|
||||
}
|
||||
|
||||
// Subscription represents a Subscription from the Azure CLI
|
||||
type Subscription struct {
|
||||
EnvironmentName string `json:"environmentName"`
|
||||
ID string `json:"id"`
|
||||
IsDefault bool `json:"isDefault"`
|
||||
Name string `json:"name"`
|
||||
State string `json:"state"`
|
||||
TenantID string `json:"tenantId"`
|
||||
User *User `json:"user"`
|
||||
}
|
||||
|
||||
// User represents a User from the Azure CLI
|
||||
type User struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
const azureProfileJSON = "azureProfile.json"
|
||||
|
||||
// ProfilePath returns the path where the Azure Profile is stored from the Azure CLI
|
||||
func ProfilePath() (string, error) {
|
||||
if cfgDir := os.Getenv("AZURE_CONFIG_DIR"); cfgDir != "" {
|
||||
return filepath.Join(cfgDir, azureProfileJSON), nil
|
||||
}
|
||||
return homedir.Expand("~/.azure/" + azureProfileJSON)
|
||||
}
|
||||
|
||||
// LoadProfile restores a Profile object from a file located at 'path'.
|
||||
func LoadProfile(path string) (result Profile, err error) {
|
||||
var contents []byte
|
||||
contents, err = ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("failed to open file (%s) while loading token: %v", path, err)
|
||||
return
|
||||
}
|
||||
reader := utfbom.SkipOnly(bytes.NewReader(contents))
|
||||
|
||||
dec := json.NewDecoder(reader)
|
||||
if err = dec.Decode(&result); err != nil {
|
||||
err = fmt.Errorf("failed to decode contents of file (%s) into a Profile representation: %v", path, err)
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
|
@ -0,0 +1,170 @@
|
|||
package cli
|
||||
|
||||
// Copyright 2017 Microsoft Corporation
|
||||
//
|
||||
// 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.
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/Azure/go-autorest/autorest/adal"
|
||||
"github.com/Azure/go-autorest/autorest/date"
|
||||
"github.com/mitchellh/go-homedir"
|
||||
)
|
||||
|
||||
// Token represents an AccessToken from the Azure CLI
|
||||
type Token struct {
|
||||
AccessToken string `json:"accessToken"`
|
||||
Authority string `json:"_authority"`
|
||||
ClientID string `json:"_clientId"`
|
||||
ExpiresOn string `json:"expiresOn"`
|
||||
IdentityProvider string `json:"identityProvider"`
|
||||
IsMRRT bool `json:"isMRRT"`
|
||||
RefreshToken string `json:"refreshToken"`
|
||||
Resource string `json:"resource"`
|
||||
TokenType string `json:"tokenType"`
|
||||
UserID string `json:"userId"`
|
||||
}
|
||||
|
||||
// ToADALToken converts an Azure CLI `Token`` to an `adal.Token``
|
||||
func (t Token) ToADALToken() (converted adal.Token, err error) {
|
||||
tokenExpirationDate, err := ParseExpirationDate(t.ExpiresOn)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("Error parsing Token Expiration Date %q: %+v", t.ExpiresOn, err)
|
||||
return
|
||||
}
|
||||
|
||||
difference := tokenExpirationDate.Sub(date.UnixEpoch())
|
||||
|
||||
converted = adal.Token{
|
||||
AccessToken: t.AccessToken,
|
||||
Type: t.TokenType,
|
||||
ExpiresIn: "3600",
|
||||
ExpiresOn: json.Number(strconv.Itoa(int(difference.Seconds()))),
|
||||
RefreshToken: t.RefreshToken,
|
||||
Resource: t.Resource,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// AccessTokensPath returns the path where access tokens are stored from the Azure CLI
|
||||
// TODO(#199): add unit test.
|
||||
func AccessTokensPath() (string, error) {
|
||||
// Azure-CLI allows user to customize the path of access tokens thorugh environment variable.
|
||||
var accessTokenPath = os.Getenv("AZURE_ACCESS_TOKEN_FILE")
|
||||
var err error
|
||||
|
||||
// Fallback logic to default path on non-cloud-shell environment.
|
||||
// TODO(#200): remove the dependency on hard-coding path.
|
||||
if accessTokenPath == "" {
|
||||
accessTokenPath, err = homedir.Expand("~/.azure/accessTokens.json")
|
||||
}
|
||||
|
||||
return accessTokenPath, err
|
||||
}
|
||||
|
||||
// ParseExpirationDate parses either a Azure CLI or CloudShell date into a time object
|
||||
func ParseExpirationDate(input string) (*time.Time, error) {
|
||||
// CloudShell (and potentially the Azure CLI in future)
|
||||
expirationDate, cloudShellErr := time.Parse(time.RFC3339, input)
|
||||
if cloudShellErr != nil {
|
||||
// Azure CLI (Python) e.g. 2017-08-31 19:48:57.998857 (plus the local timezone)
|
||||
const cliFormat = "2006-01-02 15:04:05.999999"
|
||||
expirationDate, cliErr := time.ParseInLocation(cliFormat, input, time.Local)
|
||||
if cliErr == nil {
|
||||
return &expirationDate, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("Error parsing expiration date %q.\n\nCloudShell Error: \n%+v\n\nCLI Error:\n%+v", input, cloudShellErr, cliErr)
|
||||
}
|
||||
|
||||
return &expirationDate, nil
|
||||
}
|
||||
|
||||
// LoadTokens restores a set of Token objects from a file located at 'path'.
|
||||
func LoadTokens(path string) ([]Token, error) {
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to open file (%s) while loading token: %v", path, err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
var tokens []Token
|
||||
|
||||
dec := json.NewDecoder(file)
|
||||
if err = dec.Decode(&tokens); err != nil {
|
||||
return nil, fmt.Errorf("failed to decode contents of file (%s) into a `cli.Token` representation: %v", path, err)
|
||||
}
|
||||
|
||||
return tokens, nil
|
||||
}
|
||||
|
||||
// GetTokenFromCLI gets a token using Azure CLI 2.0 for local development scenarios.
|
||||
func GetTokenFromCLI(resource string) (*Token, error) {
|
||||
// This is the path that a developer can set to tell this class what the install path for Azure CLI is.
|
||||
const azureCLIPath = "AzureCLIPath"
|
||||
|
||||
// The default install paths are used to find Azure CLI. This is for security, so that any path in the calling program's Path environment is not used to execute Azure CLI.
|
||||
azureCLIDefaultPathWindows := fmt.Sprintf("%s\\Microsoft SDKs\\Azure\\CLI2\\wbin; %s\\Microsoft SDKs\\Azure\\CLI2\\wbin", os.Getenv("ProgramFiles(x86)"), os.Getenv("ProgramFiles"))
|
||||
|
||||
// Default path for non-Windows.
|
||||
const azureCLIDefaultPath = "/bin:/sbin:/usr/bin:/usr/local/bin"
|
||||
|
||||
// Validate resource, since it gets sent as a command line argument to Azure CLI
|
||||
const invalidResourceErrorTemplate = "Resource %s is not in expected format. Only alphanumeric characters, [dot], [colon], [hyphen], and [forward slash] are allowed."
|
||||
match, err := regexp.MatchString("^[0-9a-zA-Z-.:/]+$", resource)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !match {
|
||||
return nil, fmt.Errorf(invalidResourceErrorTemplate, resource)
|
||||
}
|
||||
|
||||
// Execute Azure CLI to get token
|
||||
var cliCmd *exec.Cmd
|
||||
if runtime.GOOS == "windows" {
|
||||
cliCmd = exec.Command(fmt.Sprintf("%s\\system32\\cmd.exe", os.Getenv("windir")))
|
||||
cliCmd.Env = os.Environ()
|
||||
cliCmd.Env = append(cliCmd.Env, fmt.Sprintf("PATH=%s;%s", os.Getenv(azureCLIPath), azureCLIDefaultPathWindows))
|
||||
cliCmd.Args = append(cliCmd.Args, "/c", "az")
|
||||
} else {
|
||||
cliCmd = exec.Command("az")
|
||||
cliCmd.Env = os.Environ()
|
||||
cliCmd.Env = append(cliCmd.Env, fmt.Sprintf("PATH=%s:%s", os.Getenv(azureCLIPath), azureCLIDefaultPath))
|
||||
}
|
||||
cliCmd.Args = append(cliCmd.Args, "account", "get-access-token", "-o", "json", "--resource", resource)
|
||||
|
||||
var stderr bytes.Buffer
|
||||
cliCmd.Stderr = &stderr
|
||||
|
||||
output, err := cliCmd.Output()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Invoking Azure CLI failed with the following error: %s", stderr.String())
|
||||
}
|
||||
|
||||
tokenResponse := Token{}
|
||||
err = json.Unmarshal(output, &tokenResponse)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &tokenResponse, err
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
*.o
|
||||
*.a
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.prof
|
||||
|
||||
# Test binary, build with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
|
||||
.glide/
|
||||
|
||||
# Gogland
|
||||
.idea/
|
|
@ -0,0 +1,18 @@
|
|||
language: go
|
||||
|
||||
go:
|
||||
- '1.10'
|
||||
- '1.11'
|
||||
|
||||
# sudo=false makes the build run using a container
|
||||
sudo: false
|
||||
|
||||
before_install:
|
||||
- go get github.com/mattn/goveralls
|
||||
- go get golang.org/x/tools/cmd/cover
|
||||
- go get golang.org/x/tools/cmd/goimports
|
||||
- go get github.com/golang/lint/golint
|
||||
script:
|
||||
- gofiles=$(find ./ -name '*.go') && [ -z "$gofiles" ] || unformatted=$(goimports -l $gofiles) && [ -z "$unformatted" ] || (echo >&2 "Go files must be formatted with gofmt. Following files has problem:\n $unformatted" && false)
|
||||
- golint ./... # This won't break the build, just show warnings
|
||||
- $HOME/gopath/bin/goveralls -service=travis-ci
|
|
@ -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.
|
|
@ -0,0 +1,66 @@
|
|||
# utfbom [![Godoc](https://godoc.org/github.com/dimchansky/utfbom?status.png)](https://godoc.org/github.com/dimchansky/utfbom) [![License](https://img.shields.io/:license-apache-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![Build Status](https://travis-ci.org/dimchansky/utfbom.svg?branch=master)](https://travis-ci.org/dimchansky/utfbom) [![Go Report Card](https://goreportcard.com/badge/github.com/dimchansky/utfbom)](https://goreportcard.com/report/github.com/dimchansky/utfbom) [![Coverage Status](https://coveralls.io/repos/github/dimchansky/utfbom/badge.svg?branch=master)](https://coveralls.io/github/dimchansky/utfbom?branch=master)
|
||||
|
||||
The package utfbom implements the detection of the BOM (Unicode Byte Order Mark) and removing as necessary. It can also return the encoding detected by the BOM.
|
||||
|
||||
## Installation
|
||||
|
||||
go get -u github.com/dimchansky/utfbom
|
||||
|
||||
## Example
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/dimchansky/utfbom"
|
||||
)
|
||||
|
||||
func main() {
|
||||
trySkip([]byte("\xEF\xBB\xBFhello"))
|
||||
trySkip([]byte("hello"))
|
||||
}
|
||||
|
||||
func trySkip(byteData []byte) {
|
||||
fmt.Println("Input:", byteData)
|
||||
|
||||
// just skip BOM
|
||||
output, err := ioutil.ReadAll(utfbom.SkipOnly(bytes.NewReader(byteData)))
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
fmt.Println("ReadAll with BOM skipping", output)
|
||||
|
||||
// skip BOM and detect encoding
|
||||
sr, enc := utfbom.Skip(bytes.NewReader(byteData))
|
||||
fmt.Printf("Detected encoding: %s\n", enc)
|
||||
output, err = ioutil.ReadAll(sr)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
fmt.Println("ReadAll with BOM detection and skipping", output)
|
||||
fmt.Println()
|
||||
}
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```
|
||||
$ go run main.go
|
||||
Input: [239 187 191 104 101 108 108 111]
|
||||
ReadAll with BOM skipping [104 101 108 108 111]
|
||||
Detected encoding: UTF8
|
||||
ReadAll with BOM detection and skipping [104 101 108 108 111]
|
||||
|
||||
Input: [104 101 108 108 111]
|
||||
ReadAll with BOM skipping [104 101 108 108 111]
|
||||
Detected encoding: Unknown
|
||||
ReadAll with BOM detection and skipping [104 101 108 108 111]
|
||||
```
|
||||
|
||||
|
|
@ -0,0 +1 @@
|
|||
module github.com/dimchansky/utfbom
|
|
@ -0,0 +1,192 @@
|
|||
// Package utfbom implements the detection of the BOM (Unicode Byte Order Mark) and removing as necessary.
|
||||
// It wraps an io.Reader object, creating another object (Reader) that also implements the io.Reader
|
||||
// interface but provides automatic BOM checking and removing as necessary.
|
||||
package utfbom
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
)
|
||||
|
||||
// Encoding is type alias for detected UTF encoding.
|
||||
type Encoding int
|
||||
|
||||
// Constants to identify detected UTF encodings.
|
||||
const (
|
||||
// Unknown encoding, returned when no BOM was detected
|
||||
Unknown Encoding = iota
|
||||
|
||||
// UTF8, BOM bytes: EF BB BF
|
||||
UTF8
|
||||
|
||||
// UTF-16, big-endian, BOM bytes: FE FF
|
||||
UTF16BigEndian
|
||||
|
||||
// UTF-16, little-endian, BOM bytes: FF FE
|
||||
UTF16LittleEndian
|
||||
|
||||
// UTF-32, big-endian, BOM bytes: 00 00 FE FF
|
||||
UTF32BigEndian
|
||||
|
||||
// UTF-32, little-endian, BOM bytes: FF FE 00 00
|
||||
UTF32LittleEndian
|
||||
)
|
||||
|
||||
// String returns a user-friendly string representation of the encoding. Satisfies fmt.Stringer interface.
|
||||
func (e Encoding) String() string {
|
||||
switch e {
|
||||
case UTF8:
|
||||
return "UTF8"
|
||||
case UTF16BigEndian:
|
||||
return "UTF16BigEndian"
|
||||
case UTF16LittleEndian:
|
||||
return "UTF16LittleEndian"
|
||||
case UTF32BigEndian:
|
||||
return "UTF32BigEndian"
|
||||
case UTF32LittleEndian:
|
||||
return "UTF32LittleEndian"
|
||||
default:
|
||||
return "Unknown"
|
||||
}
|
||||
}
|
||||
|
||||
const maxConsecutiveEmptyReads = 100
|
||||
|
||||
// Skip creates Reader which automatically detects BOM (Unicode Byte Order Mark) and removes it as necessary.
|
||||
// It also returns the encoding detected by the BOM.
|
||||
// If the detected encoding is not needed, you can call the SkipOnly function.
|
||||
func Skip(rd io.Reader) (*Reader, Encoding) {
|
||||
// Is it already a Reader?
|
||||
b, ok := rd.(*Reader)
|
||||
if ok {
|
||||
return b, Unknown
|
||||
}
|
||||
|
||||
enc, left, err := detectUtf(rd)
|
||||
return &Reader{
|
||||
rd: rd,
|
||||
buf: left,
|
||||
err: err,
|
||||
}, enc
|
||||
}
|
||||
|
||||
// SkipOnly creates Reader which automatically detects BOM (Unicode Byte Order Mark) and removes it as necessary.
|
||||
func SkipOnly(rd io.Reader) *Reader {
|
||||
r, _ := Skip(rd)
|
||||
return r
|
||||
}
|
||||
|
||||
// Reader implements automatic BOM (Unicode Byte Order Mark) checking and
|
||||
// removing as necessary for an io.Reader object.
|
||||
type Reader struct {
|
||||
rd io.Reader // reader provided by the client
|
||||
buf []byte // buffered data
|
||||
err error // last error
|
||||
}
|
||||
|
||||
// Read is an implementation of io.Reader interface.
|
||||
// The bytes are taken from the underlying Reader, but it checks for BOMs, removing them as necessary.
|
||||
func (r *Reader) Read(p []byte) (n int, err error) {
|
||||
if len(p) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
if r.buf == nil {
|
||||
if r.err != nil {
|
||||
return 0, r.readErr()
|
||||
}
|
||||
|
||||
return r.rd.Read(p)
|
||||
}
|
||||
|
||||
// copy as much as we can
|
||||
n = copy(p, r.buf)
|
||||
r.buf = nilIfEmpty(r.buf[n:])
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (r *Reader) readErr() error {
|
||||
err := r.err
|
||||
r.err = nil
|
||||
return err
|
||||
}
|
||||
|
||||
var errNegativeRead = errors.New("utfbom: reader returned negative count from Read")
|
||||
|
||||
func detectUtf(rd io.Reader) (enc Encoding, buf []byte, err error) {
|
||||
buf, err = readBOM(rd)
|
||||
|
||||
if len(buf) >= 4 {
|
||||
if isUTF32BigEndianBOM4(buf) {
|
||||
return UTF32BigEndian, nilIfEmpty(buf[4:]), err
|
||||
}
|
||||
if isUTF32LittleEndianBOM4(buf) {
|
||||
return UTF32LittleEndian, nilIfEmpty(buf[4:]), err
|
||||
}
|
||||
}
|
||||
|
||||
if len(buf) > 2 && isUTF8BOM3(buf) {
|
||||
return UTF8, nilIfEmpty(buf[3:]), err
|
||||
}
|
||||
|
||||
if (err != nil && err != io.EOF) || (len(buf) < 2) {
|
||||
return Unknown, nilIfEmpty(buf), err
|
||||
}
|
||||
|
||||
if isUTF16BigEndianBOM2(buf) {
|
||||
return UTF16BigEndian, nilIfEmpty(buf[2:]), err
|
||||
}
|
||||
if isUTF16LittleEndianBOM2(buf) {
|
||||
return UTF16LittleEndian, nilIfEmpty(buf[2:]), err
|
||||
}
|
||||
|
||||
return Unknown, nilIfEmpty(buf), err
|
||||
}
|
||||
|
||||
func readBOM(rd io.Reader) (buf []byte, err error) {
|
||||
const maxBOMSize = 4
|
||||
var bom [maxBOMSize]byte // used to read BOM
|
||||
|
||||
// read as many bytes as possible
|
||||
for nEmpty, n := 0, 0; err == nil && len(buf) < maxBOMSize; buf = bom[:len(buf)+n] {
|
||||
if n, err = rd.Read(bom[len(buf):]); n < 0 {
|
||||
panic(errNegativeRead)
|
||||
}
|
||||
if n > 0 {
|
||||
nEmpty = 0
|
||||
} else {
|
||||
nEmpty++
|
||||
if nEmpty >= maxConsecutiveEmptyReads {
|
||||
err = io.ErrNoProgress
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func isUTF32BigEndianBOM4(buf []byte) bool {
|
||||
return buf[0] == 0x00 && buf[1] == 0x00 && buf[2] == 0xFE && buf[3] == 0xFF
|
||||
}
|
||||
|
||||
func isUTF32LittleEndianBOM4(buf []byte) bool {
|
||||
return buf[0] == 0xFF && buf[1] == 0xFE && buf[2] == 0x00 && buf[3] == 0x00
|
||||
}
|
||||
|
||||
func isUTF8BOM3(buf []byte) bool {
|
||||
return buf[0] == 0xEF && buf[1] == 0xBB && buf[2] == 0xBF
|
||||
}
|
||||
|
||||
func isUTF16BigEndianBOM2(buf []byte) bool {
|
||||
return buf[0] == 0xFE && buf[1] == 0xFF
|
||||
}
|
||||
|
||||
func isUTF16LittleEndianBOM2(buf []byte) bool {
|
||||
return buf[0] == 0xFF && buf[1] == 0xFE
|
||||
}
|
||||
|
||||
func nilIfEmpty(buf []byte) (res []byte) {
|
||||
if len(buf) > 0 {
|
||||
res = buf
|
||||
}
|
||||
return
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
// 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.
|
||||
|
||||
package pkcs12
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"unicode/utf16"
|
||||
)
|
||||
|
||||
// bmpString returns s encoded in UCS-2 with a zero terminator.
|
||||
func bmpString(s string) ([]byte, error) {
|
||||
// References:
|
||||
// https://tools.ietf.org/html/rfc7292#appendix-B.1
|
||||
// https://en.wikipedia.org/wiki/Plane_(Unicode)#Basic_Multilingual_Plane
|
||||
// - non-BMP characters are encoded in UTF 16 by using a surrogate pair of 16-bit codes
|
||||
// EncodeRune returns 0xfffd if the rune does not need special encoding
|
||||
// - the above RFC provides the info that BMPStrings are NULL terminated.
|
||||
|
||||
ret := make([]byte, 0, 2*len(s)+2)
|
||||
|
||||
for _, r := range s {
|
||||
if t, _ := utf16.EncodeRune(r); t != 0xfffd {
|
||||
return nil, errors.New("pkcs12: string contains characters that cannot be encoded in UCS-2")
|
||||
}
|
||||
ret = append(ret, byte(r/256), byte(r%256))
|
||||
}
|
||||
|
||||
return append(ret, 0, 0), nil
|
||||
}
|
||||
|
||||
func decodeBMPString(bmpString []byte) (string, error) {
|
||||
if len(bmpString)%2 != 0 {
|
||||
return "", errors.New("pkcs12: odd-length BMP string")
|
||||
}
|
||||
|
||||
// strip terminator if present
|
||||
if l := len(bmpString); l >= 2 && bmpString[l-1] == 0 && bmpString[l-2] == 0 {
|
||||
bmpString = bmpString[:l-2]
|
||||
}
|
||||
|
||||
s := make([]uint16, 0, len(bmpString)/2)
|
||||
for len(bmpString) > 0 {
|
||||
s = append(s, uint16(bmpString[0])<<8+uint16(bmpString[1]))
|
||||
bmpString = bmpString[2:]
|
||||
}
|
||||
|
||||
return string(utf16.Decode(s)), nil
|
||||
}
|
|
@ -0,0 +1,131 @@
|
|||
// 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.
|
||||
|
||||
package pkcs12
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/cipher"
|
||||
"crypto/des"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"errors"
|
||||
|
||||
"golang.org/x/crypto/pkcs12/internal/rc2"
|
||||
)
|
||||
|
||||
var (
|
||||
oidPBEWithSHAAnd3KeyTripleDESCBC = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 1, 3})
|
||||
oidPBEWithSHAAnd40BitRC2CBC = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 1, 6})
|
||||
)
|
||||
|
||||
// pbeCipher is an abstraction of a PKCS#12 cipher.
|
||||
type pbeCipher interface {
|
||||
// create returns a cipher.Block given a key.
|
||||
create(key []byte) (cipher.Block, error)
|
||||
// deriveKey returns a key derived from the given password and salt.
|
||||
deriveKey(salt, password []byte, iterations int) []byte
|
||||
// deriveKey returns an IV derived from the given password and salt.
|
||||
deriveIV(salt, password []byte, iterations int) []byte
|
||||
}
|
||||
|
||||
type shaWithTripleDESCBC struct{}
|
||||
|
||||
func (shaWithTripleDESCBC) create(key []byte) (cipher.Block, error) {
|
||||
return des.NewTripleDESCipher(key)
|
||||
}
|
||||
|
||||
func (shaWithTripleDESCBC) deriveKey(salt, password []byte, iterations int) []byte {
|
||||
return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 1, 24)
|
||||
}
|
||||
|
||||
func (shaWithTripleDESCBC) deriveIV(salt, password []byte, iterations int) []byte {
|
||||
return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 2, 8)
|
||||
}
|
||||
|
||||
type shaWith40BitRC2CBC struct{}
|
||||
|
||||
func (shaWith40BitRC2CBC) create(key []byte) (cipher.Block, error) {
|
||||
return rc2.New(key, len(key)*8)
|
||||
}
|
||||
|
||||
func (shaWith40BitRC2CBC) deriveKey(salt, password []byte, iterations int) []byte {
|
||||
return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 1, 5)
|
||||
}
|
||||
|
||||
func (shaWith40BitRC2CBC) deriveIV(salt, password []byte, iterations int) []byte {
|
||||
return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 2, 8)
|
||||
}
|
||||
|
||||
type pbeParams struct {
|
||||
Salt []byte
|
||||
Iterations int
|
||||
}
|
||||
|
||||
func pbDecrypterFor(algorithm pkix.AlgorithmIdentifier, password []byte) (cipher.BlockMode, int, error) {
|
||||
var cipherType pbeCipher
|
||||
|
||||
switch {
|
||||
case algorithm.Algorithm.Equal(oidPBEWithSHAAnd3KeyTripleDESCBC):
|
||||
cipherType = shaWithTripleDESCBC{}
|
||||
case algorithm.Algorithm.Equal(oidPBEWithSHAAnd40BitRC2CBC):
|
||||
cipherType = shaWith40BitRC2CBC{}
|
||||
default:
|
||||
return nil, 0, NotImplementedError("algorithm " + algorithm.Algorithm.String() + " is not supported")
|
||||
}
|
||||
|
||||
var params pbeParams
|
||||
if err := unmarshal(algorithm.Parameters.FullBytes, ¶ms); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
key := cipherType.deriveKey(params.Salt, password, params.Iterations)
|
||||
iv := cipherType.deriveIV(params.Salt, password, params.Iterations)
|
||||
|
||||
block, err := cipherType.create(key)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return cipher.NewCBCDecrypter(block, iv), block.BlockSize(), nil
|
||||
}
|
||||
|
||||
func pbDecrypt(info decryptable, password []byte) (decrypted []byte, err error) {
|
||||
cbc, blockSize, err := pbDecrypterFor(info.Algorithm(), password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
encrypted := info.Data()
|
||||
if len(encrypted) == 0 {
|
||||
return nil, errors.New("pkcs12: empty encrypted data")
|
||||
}
|
||||
if len(encrypted)%blockSize != 0 {
|
||||
return nil, errors.New("pkcs12: input is not a multiple of the block size")
|
||||
}
|
||||
decrypted = make([]byte, len(encrypted))
|
||||
cbc.CryptBlocks(decrypted, encrypted)
|
||||
|
||||
psLen := int(decrypted[len(decrypted)-1])
|
||||
if psLen == 0 || psLen > blockSize {
|
||||
return nil, ErrDecryption
|
||||
}
|
||||
|
||||
if len(decrypted) < psLen {
|
||||
return nil, ErrDecryption
|
||||
}
|
||||
ps := decrypted[len(decrypted)-psLen:]
|
||||
decrypted = decrypted[:len(decrypted)-psLen]
|
||||
if bytes.Compare(ps, bytes.Repeat([]byte{byte(psLen)}, psLen)) != 0 {
|
||||
return nil, ErrDecryption
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// decryptable abstracts an object that contains ciphertext.
|
||||
type decryptable interface {
|
||||
Algorithm() pkix.AlgorithmIdentifier
|
||||
Data() []byte
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
// 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.
|
||||
|
||||
package pkcs12
|
||||
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
// ErrDecryption represents a failure to decrypt the input.
|
||||
ErrDecryption = errors.New("pkcs12: decryption error, incorrect padding")
|
||||
|
||||
// ErrIncorrectPassword is returned when an incorrect password is detected.
|
||||
// Usually, P12/PFX data is signed to be able to verify the password.
|
||||
ErrIncorrectPassword = errors.New("pkcs12: decryption password incorrect")
|
||||
)
|
||||
|
||||
// NotImplementedError indicates that the input is not currently supported.
|
||||
type NotImplementedError string
|
||||
|
||||
func (e NotImplementedError) Error() string {
|
||||
return "pkcs12: " + string(e)
|
||||
}
|
|
@ -0,0 +1,271 @@
|
|||
// 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.
|
||||
|
||||
// Package rc2 implements the RC2 cipher
|
||||
/*
|
||||
https://www.ietf.org/rfc/rfc2268.txt
|
||||
http://people.csail.mit.edu/rivest/pubs/KRRR98.pdf
|
||||
|
||||
This code is licensed under the MIT license.
|
||||
*/
|
||||
package rc2
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"encoding/binary"
|
||||
)
|
||||
|
||||
// The rc2 block size in bytes
|
||||
const BlockSize = 8
|
||||
|
||||
type rc2Cipher struct {
|
||||
k [64]uint16
|
||||
}
|
||||
|
||||
// New returns a new rc2 cipher with the given key and effective key length t1
|
||||
func New(key []byte, t1 int) (cipher.Block, error) {
|
||||
// TODO(dgryski): error checking for key length
|
||||
return &rc2Cipher{
|
||||
k: expandKey(key, t1),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (*rc2Cipher) BlockSize() int { return BlockSize }
|
||||
|
||||
var piTable = [256]byte{
|
||||
0xd9, 0x78, 0xf9, 0xc4, 0x19, 0xdd, 0xb5, 0xed, 0x28, 0xe9, 0xfd, 0x79, 0x4a, 0xa0, 0xd8, 0x9d,
|
||||
0xc6, 0x7e, 0x37, 0x83, 0x2b, 0x76, 0x53, 0x8e, 0x62, 0x4c, 0x64, 0x88, 0x44, 0x8b, 0xfb, 0xa2,
|
||||
0x17, 0x9a, 0x59, 0xf5, 0x87, 0xb3, 0x4f, 0x13, 0x61, 0x45, 0x6d, 0x8d, 0x09, 0x81, 0x7d, 0x32,
|
||||
0xbd, 0x8f, 0x40, 0xeb, 0x86, 0xb7, 0x7b, 0x0b, 0xf0, 0x95, 0x21, 0x22, 0x5c, 0x6b, 0x4e, 0x82,
|
||||
0x54, 0xd6, 0x65, 0x93, 0xce, 0x60, 0xb2, 0x1c, 0x73, 0x56, 0xc0, 0x14, 0xa7, 0x8c, 0xf1, 0xdc,
|
||||
0x12, 0x75, 0xca, 0x1f, 0x3b, 0xbe, 0xe4, 0xd1, 0x42, 0x3d, 0xd4, 0x30, 0xa3, 0x3c, 0xb6, 0x26,
|
||||
0x6f, 0xbf, 0x0e, 0xda, 0x46, 0x69, 0x07, 0x57, 0x27, 0xf2, 0x1d, 0x9b, 0xbc, 0x94, 0x43, 0x03,
|
||||
0xf8, 0x11, 0xc7, 0xf6, 0x90, 0xef, 0x3e, 0xe7, 0x06, 0xc3, 0xd5, 0x2f, 0xc8, 0x66, 0x1e, 0xd7,
|
||||
0x08, 0xe8, 0xea, 0xde, 0x80, 0x52, 0xee, 0xf7, 0x84, 0xaa, 0x72, 0xac, 0x35, 0x4d, 0x6a, 0x2a,
|
||||
0x96, 0x1a, 0xd2, 0x71, 0x5a, 0x15, 0x49, 0x74, 0x4b, 0x9f, 0xd0, 0x5e, 0x04, 0x18, 0xa4, 0xec,
|
||||
0xc2, 0xe0, 0x41, 0x6e, 0x0f, 0x51, 0xcb, 0xcc, 0x24, 0x91, 0xaf, 0x50, 0xa1, 0xf4, 0x70, 0x39,
|
||||
0x99, 0x7c, 0x3a, 0x85, 0x23, 0xb8, 0xb4, 0x7a, 0xfc, 0x02, 0x36, 0x5b, 0x25, 0x55, 0x97, 0x31,
|
||||
0x2d, 0x5d, 0xfa, 0x98, 0xe3, 0x8a, 0x92, 0xae, 0x05, 0xdf, 0x29, 0x10, 0x67, 0x6c, 0xba, 0xc9,
|
||||
0xd3, 0x00, 0xe6, 0xcf, 0xe1, 0x9e, 0xa8, 0x2c, 0x63, 0x16, 0x01, 0x3f, 0x58, 0xe2, 0x89, 0xa9,
|
||||
0x0d, 0x38, 0x34, 0x1b, 0xab, 0x33, 0xff, 0xb0, 0xbb, 0x48, 0x0c, 0x5f, 0xb9, 0xb1, 0xcd, 0x2e,
|
||||
0xc5, 0xf3, 0xdb, 0x47, 0xe5, 0xa5, 0x9c, 0x77, 0x0a, 0xa6, 0x20, 0x68, 0xfe, 0x7f, 0xc1, 0xad,
|
||||
}
|
||||
|
||||
func expandKey(key []byte, t1 int) [64]uint16 {
|
||||
|
||||
l := make([]byte, 128)
|
||||
copy(l, key)
|
||||
|
||||
var t = len(key)
|
||||
var t8 = (t1 + 7) / 8
|
||||
var tm = byte(255 % uint(1<<(8+uint(t1)-8*uint(t8))))
|
||||
|
||||
for i := len(key); i < 128; i++ {
|
||||
l[i] = piTable[l[i-1]+l[uint8(i-t)]]
|
||||
}
|
||||
|
||||
l[128-t8] = piTable[l[128-t8]&tm]
|
||||
|
||||
for i := 127 - t8; i >= 0; i-- {
|
||||
l[i] = piTable[l[i+1]^l[i+t8]]
|
||||
}
|
||||
|
||||
var k [64]uint16
|
||||
|
||||
for i := range k {
|
||||
k[i] = uint16(l[2*i]) + uint16(l[2*i+1])*256
|
||||
}
|
||||
|
||||
return k
|
||||
}
|
||||
|
||||
func rotl16(x uint16, b uint) uint16 {
|
||||
return (x >> (16 - b)) | (x << b)
|
||||
}
|
||||
|
||||
func (c *rc2Cipher) Encrypt(dst, src []byte) {
|
||||
|
||||
r0 := binary.LittleEndian.Uint16(src[0:])
|
||||
r1 := binary.LittleEndian.Uint16(src[2:])
|
||||
r2 := binary.LittleEndian.Uint16(src[4:])
|
||||
r3 := binary.LittleEndian.Uint16(src[6:])
|
||||
|
||||
var j int
|
||||
|
||||
for j <= 16 {
|
||||
// mix r0
|
||||
r0 = r0 + c.k[j] + (r3 & r2) + ((^r3) & r1)
|
||||
r0 = rotl16(r0, 1)
|
||||
j++
|
||||
|
||||
// mix r1
|
||||
r1 = r1 + c.k[j] + (r0 & r3) + ((^r0) & r2)
|
||||
r1 = rotl16(r1, 2)
|
||||
j++
|
||||
|
||||
// mix r2
|
||||
r2 = r2 + c.k[j] + (r1 & r0) + ((^r1) & r3)
|
||||
r2 = rotl16(r2, 3)
|
||||
j++
|
||||
|
||||
// mix r3
|
||||
r3 = r3 + c.k[j] + (r2 & r1) + ((^r2) & r0)
|
||||
r3 = rotl16(r3, 5)
|
||||
j++
|
||||
|
||||
}
|
||||
|
||||
r0 = r0 + c.k[r3&63]
|
||||
r1 = r1 + c.k[r0&63]
|
||||
r2 = r2 + c.k[r1&63]
|
||||
r3 = r3 + c.k[r2&63]
|
||||
|
||||
for j <= 40 {
|
||||
// mix r0
|
||||
r0 = r0 + c.k[j] + (r3 & r2) + ((^r3) & r1)
|
||||
r0 = rotl16(r0, 1)
|
||||
j++
|
||||
|
||||
// mix r1
|
||||
r1 = r1 + c.k[j] + (r0 & r3) + ((^r0) & r2)
|
||||
r1 = rotl16(r1, 2)
|
||||
j++
|
||||
|
||||
// mix r2
|
||||
r2 = r2 + c.k[j] + (r1 & r0) + ((^r1) & r3)
|
||||
r2 = rotl16(r2, 3)
|
||||
j++
|
||||
|
||||
// mix r3
|
||||
r3 = r3 + c.k[j] + (r2 & r1) + ((^r2) & r0)
|
||||
r3 = rotl16(r3, 5)
|
||||
j++
|
||||
|
||||
}
|
||||
|
||||
r0 = r0 + c.k[r3&63]
|
||||
r1 = r1 + c.k[r0&63]
|
||||
r2 = r2 + c.k[r1&63]
|
||||
r3 = r3 + c.k[r2&63]
|
||||
|
||||
for j <= 60 {
|
||||
// mix r0
|
||||
r0 = r0 + c.k[j] + (r3 & r2) + ((^r3) & r1)
|
||||
r0 = rotl16(r0, 1)
|
||||
j++
|
||||
|
||||
// mix r1
|
||||
r1 = r1 + c.k[j] + (r0 & r3) + ((^r0) & r2)
|
||||
r1 = rotl16(r1, 2)
|
||||
j++
|
||||
|
||||
// mix r2
|
||||
r2 = r2 + c.k[j] + (r1 & r0) + ((^r1) & r3)
|
||||
r2 = rotl16(r2, 3)
|
||||
j++
|
||||
|
||||
// mix r3
|
||||
r3 = r3 + c.k[j] + (r2 & r1) + ((^r2) & r0)
|
||||
r3 = rotl16(r3, 5)
|
||||
j++
|
||||
}
|
||||
|
||||
binary.LittleEndian.PutUint16(dst[0:], r0)
|
||||
binary.LittleEndian.PutUint16(dst[2:], r1)
|
||||
binary.LittleEndian.PutUint16(dst[4:], r2)
|
||||
binary.LittleEndian.PutUint16(dst[6:], r3)
|
||||
}
|
||||
|
||||
func (c *rc2Cipher) Decrypt(dst, src []byte) {
|
||||
|
||||
r0 := binary.LittleEndian.Uint16(src[0:])
|
||||
r1 := binary.LittleEndian.Uint16(src[2:])
|
||||
r2 := binary.LittleEndian.Uint16(src[4:])
|
||||
r3 := binary.LittleEndian.Uint16(src[6:])
|
||||
|
||||
j := 63
|
||||
|
||||
for j >= 44 {
|
||||
// unmix r3
|
||||
r3 = rotl16(r3, 16-5)
|
||||
r3 = r3 - c.k[j] - (r2 & r1) - ((^r2) & r0)
|
||||
j--
|
||||
|
||||
// unmix r2
|
||||
r2 = rotl16(r2, 16-3)
|
||||
r2 = r2 - c.k[j] - (r1 & r0) - ((^r1) & r3)
|
||||
j--
|
||||
|
||||
// unmix r1
|
||||
r1 = rotl16(r1, 16-2)
|
||||
r1 = r1 - c.k[j] - (r0 & r3) - ((^r0) & r2)
|
||||
j--
|
||||
|
||||
// unmix r0
|
||||
r0 = rotl16(r0, 16-1)
|
||||
r0 = r0 - c.k[j] - (r3 & r2) - ((^r3) & r1)
|
||||
j--
|
||||
}
|
||||
|
||||
r3 = r3 - c.k[r2&63]
|
||||
r2 = r2 - c.k[r1&63]
|
||||
r1 = r1 - c.k[r0&63]
|
||||
r0 = r0 - c.k[r3&63]
|
||||
|
||||
for j >= 20 {
|
||||
// unmix r3
|
||||
r3 = rotl16(r3, 16-5)
|
||||
r3 = r3 - c.k[j] - (r2 & r1) - ((^r2) & r0)
|
||||
j--
|
||||
|
||||
// unmix r2
|
||||
r2 = rotl16(r2, 16-3)
|
||||
r2 = r2 - c.k[j] - (r1 & r0) - ((^r1) & r3)
|
||||
j--
|
||||
|
||||
// unmix r1
|
||||
r1 = rotl16(r1, 16-2)
|
||||
r1 = r1 - c.k[j] - (r0 & r3) - ((^r0) & r2)
|
||||
j--
|
||||
|
||||
// unmix r0
|
||||
r0 = rotl16(r0, 16-1)
|
||||
r0 = r0 - c.k[j] - (r3 & r2) - ((^r3) & r1)
|
||||
j--
|
||||
|
||||
}
|
||||
|
||||
r3 = r3 - c.k[r2&63]
|
||||
r2 = r2 - c.k[r1&63]
|
||||
r1 = r1 - c.k[r0&63]
|
||||
r0 = r0 - c.k[r3&63]
|
||||
|
||||
for j >= 0 {
|
||||
// unmix r3
|
||||
r3 = rotl16(r3, 16-5)
|
||||
r3 = r3 - c.k[j] - (r2 & r1) - ((^r2) & r0)
|
||||
j--
|
||||
|
||||
// unmix r2
|
||||
r2 = rotl16(r2, 16-3)
|
||||
r2 = r2 - c.k[j] - (r1 & r0) - ((^r1) & r3)
|
||||
j--
|
||||
|
||||
// unmix r1
|
||||
r1 = rotl16(r1, 16-2)
|
||||
r1 = r1 - c.k[j] - (r0 & r3) - ((^r0) & r2)
|
||||
j--
|
||||
|
||||
// unmix r0
|
||||
r0 = rotl16(r0, 16-1)
|
||||
r0 = r0 - c.k[j] - (r3 & r2) - ((^r3) & r1)
|
||||
j--
|
||||
|
||||
}
|
||||
|
||||
binary.LittleEndian.PutUint16(dst[0:], r0)
|
||||
binary.LittleEndian.PutUint16(dst[2:], r1)
|
||||
binary.LittleEndian.PutUint16(dst[4:], r2)
|
||||
binary.LittleEndian.PutUint16(dst[6:], r3)
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
// 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.
|
||||
|
||||
package pkcs12
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/sha1"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
)
|
||||
|
||||
type macData struct {
|
||||
Mac digestInfo
|
||||
MacSalt []byte
|
||||
Iterations int `asn1:"optional,default:1"`
|
||||
}
|
||||
|
||||
// from PKCS#7:
|
||||
type digestInfo struct {
|
||||
Algorithm pkix.AlgorithmIdentifier
|
||||
Digest []byte
|
||||
}
|
||||
|
||||
var (
|
||||
oidSHA1 = asn1.ObjectIdentifier([]int{1, 3, 14, 3, 2, 26})
|
||||
)
|
||||
|
||||
func verifyMac(macData *macData, message, password []byte) error {
|
||||
if !macData.Mac.Algorithm.Algorithm.Equal(oidSHA1) {
|
||||
return NotImplementedError("unknown digest algorithm: " + macData.Mac.Algorithm.Algorithm.String())
|
||||
}
|
||||
|
||||
key := pbkdf(sha1Sum, 20, 64, macData.MacSalt, password, macData.Iterations, 3, 20)
|
||||
|
||||
mac := hmac.New(sha1.New, key)
|
||||
mac.Write(message)
|
||||
expectedMAC := mac.Sum(nil)
|
||||
|
||||
if !hmac.Equal(macData.Mac.Digest, expectedMAC) {
|
||||
return ErrIncorrectPassword
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,170 @@
|
|||
// 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.
|
||||
|
||||
package pkcs12
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha1"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
var (
|
||||
one = big.NewInt(1)
|
||||
)
|
||||
|
||||
// sha1Sum returns the SHA-1 hash of in.
|
||||
func sha1Sum(in []byte) []byte {
|
||||
sum := sha1.Sum(in)
|
||||
return sum[:]
|
||||
}
|
||||
|
||||
// fillWithRepeats returns v*ceiling(len(pattern) / v) bytes consisting of
|
||||
// repeats of pattern.
|
||||
func fillWithRepeats(pattern []byte, v int) []byte {
|
||||
if len(pattern) == 0 {
|
||||
return nil
|
||||
}
|
||||
outputLen := v * ((len(pattern) + v - 1) / v)
|
||||
return bytes.Repeat(pattern, (outputLen+len(pattern)-1)/len(pattern))[:outputLen]
|
||||
}
|
||||
|
||||
func pbkdf(hash func([]byte) []byte, u, v int, salt, password []byte, r int, ID byte, size int) (key []byte) {
|
||||
// implementation of https://tools.ietf.org/html/rfc7292#appendix-B.2 , RFC text verbatim in comments
|
||||
|
||||
// Let H be a hash function built around a compression function f:
|
||||
|
||||
// Z_2^u x Z_2^v -> Z_2^u
|
||||
|
||||
// (that is, H has a chaining variable and output of length u bits, and
|
||||
// the message input to the compression function of H is v bits). The
|
||||
// values for u and v are as follows:
|
||||
|
||||
// HASH FUNCTION VALUE u VALUE v
|
||||
// MD2, MD5 128 512
|
||||
// SHA-1 160 512
|
||||
// SHA-224 224 512
|
||||
// SHA-256 256 512
|
||||
// SHA-384 384 1024
|
||||
// SHA-512 512 1024
|
||||
// SHA-512/224 224 1024
|
||||
// SHA-512/256 256 1024
|
||||
|
||||
// Furthermore, let r be the iteration count.
|
||||
|
||||
// We assume here that u and v are both multiples of 8, as are the
|
||||
// lengths of the password and salt strings (which we denote by p and s,
|
||||
// respectively) and the number n of pseudorandom bits required. In
|
||||
// addition, u and v are of course non-zero.
|
||||
|
||||
// For information on security considerations for MD5 [19], see [25] and
|
||||
// [1], and on those for MD2, see [18].
|
||||
|
||||
// The following procedure can be used to produce pseudorandom bits for
|
||||
// a particular "purpose" that is identified by a byte called "ID".
|
||||
// This standard specifies 3 different values for the ID byte:
|
||||
|
||||
// 1. If ID=1, then the pseudorandom bits being produced are to be used
|
||||
// as key material for performing encryption or decryption.
|
||||
|
||||
// 2. If ID=2, then the pseudorandom bits being produced are to be used
|
||||
// as an IV (Initial Value) for encryption or decryption.
|
||||
|
||||
// 3. If ID=3, then the pseudorandom bits being produced are to be used
|
||||
// as an integrity key for MACing.
|
||||
|
||||
// 1. Construct a string, D (the "diversifier"), by concatenating v/8
|
||||
// copies of ID.
|
||||
var D []byte
|
||||
for i := 0; i < v; i++ {
|
||||
D = append(D, ID)
|
||||
}
|
||||
|
||||
// 2. Concatenate copies of the salt together to create a string S of
|
||||
// length v(ceiling(s/v)) bits (the final copy of the salt may be
|
||||
// truncated to create S). Note that if the salt is the empty
|
||||
// string, then so is S.
|
||||
|
||||
S := fillWithRepeats(salt, v)
|
||||
|
||||
// 3. Concatenate copies of the password together to create a string P
|
||||
// of length v(ceiling(p/v)) bits (the final copy of the password
|
||||
// may be truncated to create P). Note that if the password is the
|
||||
// empty string, then so is P.
|
||||
|
||||
P := fillWithRepeats(password, v)
|
||||
|
||||
// 4. Set I=S||P to be the concatenation of S and P.
|
||||
I := append(S, P...)
|
||||
|
||||
// 5. Set c=ceiling(n/u).
|
||||
c := (size + u - 1) / u
|
||||
|
||||
// 6. For i=1, 2, ..., c, do the following:
|
||||
A := make([]byte, c*20)
|
||||
var IjBuf []byte
|
||||
for i := 0; i < c; i++ {
|
||||
// A. Set A2=H^r(D||I). (i.e., the r-th hash of D||1,
|
||||
// H(H(H(... H(D||I))))
|
||||
Ai := hash(append(D, I...))
|
||||
for j := 1; j < r; j++ {
|
||||
Ai = hash(Ai)
|
||||
}
|
||||
copy(A[i*20:], Ai[:])
|
||||
|
||||
if i < c-1 { // skip on last iteration
|
||||
// B. Concatenate copies of Ai to create a string B of length v
|
||||
// bits (the final copy of Ai may be truncated to create B).
|
||||
var B []byte
|
||||
for len(B) < v {
|
||||
B = append(B, Ai[:]...)
|
||||
}
|
||||
B = B[:v]
|
||||
|
||||
// C. Treating I as a concatenation I_0, I_1, ..., I_(k-1) of v-bit
|
||||
// blocks, where k=ceiling(s/v)+ceiling(p/v), modify I by
|
||||
// setting I_j=(I_j+B+1) mod 2^v for each j.
|
||||
{
|
||||
Bbi := new(big.Int).SetBytes(B)
|
||||
Ij := new(big.Int)
|
||||
|
||||
for j := 0; j < len(I)/v; j++ {
|
||||
Ij.SetBytes(I[j*v : (j+1)*v])
|
||||
Ij.Add(Ij, Bbi)
|
||||
Ij.Add(Ij, one)
|
||||
Ijb := Ij.Bytes()
|
||||
// We expect Ijb to be exactly v bytes,
|
||||
// if it is longer or shorter we must
|
||||
// adjust it accordingly.
|
||||
if len(Ijb) > v {
|
||||
Ijb = Ijb[len(Ijb)-v:]
|
||||
}
|
||||
if len(Ijb) < v {
|
||||
if IjBuf == nil {
|
||||
IjBuf = make([]byte, v)
|
||||
}
|
||||
bytesShort := v - len(Ijb)
|
||||
for i := 0; i < bytesShort; i++ {
|
||||
IjBuf[i] = 0
|
||||
}
|
||||
copy(IjBuf[bytesShort:], Ijb)
|
||||
Ijb = IjBuf
|
||||
}
|
||||
copy(I[j*v:(j+1)*v], Ijb)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 7. Concatenate A_1, A_2, ..., A_c together to form a pseudorandom
|
||||
// bit string, A.
|
||||
|
||||
// 8. Use the first n bits of A as the output of this entire process.
|
||||
return A[:size]
|
||||
|
||||
// If the above process is being used to generate a DES key, the process
|
||||
// should be used to create 64 random bits, and the key's parity bits
|
||||
// should be set after the 64 bits have been produced. Similar concerns
|
||||
// hold for 2-key and 3-key triple-DES keys, for CDMF keys, and for any
|
||||
// similar keys with parity bits "built into them".
|
||||
}
|
|
@ -0,0 +1,349 @@
|
|||
// 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.
|
||||
|
||||
// Package pkcs12 implements some of PKCS#12.
|
||||
//
|
||||
// This implementation is distilled from https://tools.ietf.org/html/rfc7292
|
||||
// and referenced documents. It is intended for decoding P12/PFX-stored
|
||||
// certificates and keys for use with the crypto/tls package.
|
||||
//
|
||||
// This package is frozen. If it's missing functionality you need, consider
|
||||
// an alternative like software.sslmate.com/src/go-pkcs12.
|
||||
package pkcs12
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"encoding/hex"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
)
|
||||
|
||||
var (
|
||||
oidDataContentType = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 7, 1})
|
||||
oidEncryptedDataContentType = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 7, 6})
|
||||
|
||||
oidFriendlyName = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 9, 20})
|
||||
oidLocalKeyID = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 9, 21})
|
||||
oidMicrosoftCSPName = asn1.ObjectIdentifier([]int{1, 3, 6, 1, 4, 1, 311, 17, 1})
|
||||
)
|
||||
|
||||
type pfxPdu struct {
|
||||
Version int
|
||||
AuthSafe contentInfo
|
||||
MacData macData `asn1:"optional"`
|
||||
}
|
||||
|
||||
type contentInfo struct {
|
||||
ContentType asn1.ObjectIdentifier
|
||||
Content asn1.RawValue `asn1:"tag:0,explicit,optional"`
|
||||
}
|
||||
|
||||
type encryptedData struct {
|
||||
Version int
|
||||
EncryptedContentInfo encryptedContentInfo
|
||||
}
|
||||
|
||||
type encryptedContentInfo struct {
|
||||
ContentType asn1.ObjectIdentifier
|
||||
ContentEncryptionAlgorithm pkix.AlgorithmIdentifier
|
||||
EncryptedContent []byte `asn1:"tag:0,optional"`
|
||||
}
|
||||
|
||||
func (i encryptedContentInfo) Algorithm() pkix.AlgorithmIdentifier {
|
||||
return i.ContentEncryptionAlgorithm
|
||||
}
|
||||
|
||||
func (i encryptedContentInfo) Data() []byte { return i.EncryptedContent }
|
||||
|
||||
type safeBag struct {
|
||||
Id asn1.ObjectIdentifier
|
||||
Value asn1.RawValue `asn1:"tag:0,explicit"`
|
||||
Attributes []pkcs12Attribute `asn1:"set,optional"`
|
||||
}
|
||||
|
||||
type pkcs12Attribute struct {
|
||||
Id asn1.ObjectIdentifier
|
||||
Value asn1.RawValue `asn1:"set"`
|
||||
}
|
||||
|
||||
type encryptedPrivateKeyInfo struct {
|
||||
AlgorithmIdentifier pkix.AlgorithmIdentifier
|
||||
EncryptedData []byte
|
||||
}
|
||||
|
||||
func (i encryptedPrivateKeyInfo) Algorithm() pkix.AlgorithmIdentifier {
|
||||
return i.AlgorithmIdentifier
|
||||
}
|
||||
|
||||
func (i encryptedPrivateKeyInfo) Data() []byte {
|
||||
return i.EncryptedData
|
||||
}
|
||||
|
||||
// PEM block types
|
||||
const (
|
||||
certificateType = "CERTIFICATE"
|
||||
privateKeyType = "PRIVATE KEY"
|
||||
)
|
||||
|
||||
// unmarshal calls asn1.Unmarshal, but also returns an error if there is any
|
||||
// trailing data after unmarshaling.
|
||||
func unmarshal(in []byte, out interface{}) error {
|
||||
trailing, err := asn1.Unmarshal(in, out)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(trailing) != 0 {
|
||||
return errors.New("pkcs12: trailing data found")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ToPEM converts all "safe bags" contained in pfxData to PEM blocks.
|
||||
func ToPEM(pfxData []byte, password string) ([]*pem.Block, error) {
|
||||
encodedPassword, err := bmpString(password)
|
||||
if err != nil {
|
||||
return nil, ErrIncorrectPassword
|
||||
}
|
||||
|
||||
bags, encodedPassword, err := getSafeContents(pfxData, encodedPassword)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
blocks := make([]*pem.Block, 0, len(bags))
|
||||
for _, bag := range bags {
|
||||
block, err := convertBag(&bag, encodedPassword)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
blocks = append(blocks, block)
|
||||
}
|
||||
|
||||
return blocks, nil
|
||||
}
|
||||
|
||||
func convertBag(bag *safeBag, password []byte) (*pem.Block, error) {
|
||||
block := &pem.Block{
|
||||
Headers: make(map[string]string),
|
||||
}
|
||||
|
||||
for _, attribute := range bag.Attributes {
|
||||
k, v, err := convertAttribute(&attribute)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
block.Headers[k] = v
|
||||
}
|
||||
|
||||
switch {
|
||||
case bag.Id.Equal(oidCertBag):
|
||||
block.Type = certificateType
|
||||
certsData, err := decodeCertBag(bag.Value.Bytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
block.Bytes = certsData
|
||||
case bag.Id.Equal(oidPKCS8ShroundedKeyBag):
|
||||
block.Type = privateKeyType
|
||||
|
||||
key, err := decodePkcs8ShroudedKeyBag(bag.Value.Bytes, password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch key := key.(type) {
|
||||
case *rsa.PrivateKey:
|
||||
block.Bytes = x509.MarshalPKCS1PrivateKey(key)
|
||||
case *ecdsa.PrivateKey:
|
||||
block.Bytes, err = x509.MarshalECPrivateKey(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
default:
|
||||
return nil, errors.New("found unknown private key type in PKCS#8 wrapping")
|
||||
}
|
||||
default:
|
||||
return nil, errors.New("don't know how to convert a safe bag of type " + bag.Id.String())
|
||||
}
|
||||
return block, nil
|
||||
}
|
||||
|
||||
func convertAttribute(attribute *pkcs12Attribute) (key, value string, err error) {
|
||||
isString := false
|
||||
|
||||
switch {
|
||||
case attribute.Id.Equal(oidFriendlyName):
|
||||
key = "friendlyName"
|
||||
isString = true
|
||||
case attribute.Id.Equal(oidLocalKeyID):
|
||||
key = "localKeyId"
|
||||
case attribute.Id.Equal(oidMicrosoftCSPName):
|
||||
// This key is chosen to match OpenSSL.
|
||||
key = "Microsoft CSP Name"
|
||||
isString = true
|
||||
default:
|
||||
return "", "", errors.New("pkcs12: unknown attribute with OID " + attribute.Id.String())
|
||||
}
|
||||
|
||||
if isString {
|
||||
if err := unmarshal(attribute.Value.Bytes, &attribute.Value); err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
if value, err = decodeBMPString(attribute.Value.Bytes); err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
} else {
|
||||
var id []byte
|
||||
if err := unmarshal(attribute.Value.Bytes, &id); err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
value = hex.EncodeToString(id)
|
||||
}
|
||||
|
||||
return key, value, nil
|
||||
}
|
||||
|
||||
// Decode extracts a certificate and private key from pfxData. This function
|
||||
// assumes that there is only one certificate and only one private key in the
|
||||
// pfxData; if there are more use ToPEM instead.
|
||||
func Decode(pfxData []byte, password string) (privateKey interface{}, certificate *x509.Certificate, err error) {
|
||||
encodedPassword, err := bmpString(password)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
bags, encodedPassword, err := getSafeContents(pfxData, encodedPassword)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if len(bags) != 2 {
|
||||
err = errors.New("pkcs12: expected exactly two safe bags in the PFX PDU")
|
||||
return
|
||||
}
|
||||
|
||||
for _, bag := range bags {
|
||||
switch {
|
||||
case bag.Id.Equal(oidCertBag):
|
||||
if certificate != nil {
|
||||
err = errors.New("pkcs12: expected exactly one certificate bag")
|
||||
}
|
||||
|
||||
certsData, err := decodeCertBag(bag.Value.Bytes)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
certs, err := x509.ParseCertificates(certsData)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if len(certs) != 1 {
|
||||
err = errors.New("pkcs12: expected exactly one certificate in the certBag")
|
||||
return nil, nil, err
|
||||
}
|
||||
certificate = certs[0]
|
||||
|
||||
case bag.Id.Equal(oidPKCS8ShroundedKeyBag):
|
||||
if privateKey != nil {
|
||||
err = errors.New("pkcs12: expected exactly one key bag")
|
||||
}
|
||||
|
||||
if privateKey, err = decodePkcs8ShroudedKeyBag(bag.Value.Bytes, encodedPassword); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if certificate == nil {
|
||||
return nil, nil, errors.New("pkcs12: certificate missing")
|
||||
}
|
||||
if privateKey == nil {
|
||||
return nil, nil, errors.New("pkcs12: private key missing")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func getSafeContents(p12Data, password []byte) (bags []safeBag, updatedPassword []byte, err error) {
|
||||
pfx := new(pfxPdu)
|
||||
if err := unmarshal(p12Data, pfx); err != nil {
|
||||
return nil, nil, errors.New("pkcs12: error reading P12 data: " + err.Error())
|
||||
}
|
||||
|
||||
if pfx.Version != 3 {
|
||||
return nil, nil, NotImplementedError("can only decode v3 PFX PDU's")
|
||||
}
|
||||
|
||||
if !pfx.AuthSafe.ContentType.Equal(oidDataContentType) {
|
||||
return nil, nil, NotImplementedError("only password-protected PFX is implemented")
|
||||
}
|
||||
|
||||
// unmarshal the explicit bytes in the content for type 'data'
|
||||
if err := unmarshal(pfx.AuthSafe.Content.Bytes, &pfx.AuthSafe.Content); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if len(pfx.MacData.Mac.Algorithm.Algorithm) == 0 {
|
||||
return nil, nil, errors.New("pkcs12: no MAC in data")
|
||||
}
|
||||
|
||||
if err := verifyMac(&pfx.MacData, pfx.AuthSafe.Content.Bytes, password); err != nil {
|
||||
if err == ErrIncorrectPassword && len(password) == 2 && password[0] == 0 && password[1] == 0 {
|
||||
// some implementations use an empty byte array
|
||||
// for the empty string password try one more
|
||||
// time with empty-empty password
|
||||
password = nil
|
||||
err = verifyMac(&pfx.MacData, pfx.AuthSafe.Content.Bytes, password)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var authenticatedSafe []contentInfo
|
||||
if err := unmarshal(pfx.AuthSafe.Content.Bytes, &authenticatedSafe); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if len(authenticatedSafe) != 2 {
|
||||
return nil, nil, NotImplementedError("expected exactly two items in the authenticated safe")
|
||||
}
|
||||
|
||||
for _, ci := range authenticatedSafe {
|
||||
var data []byte
|
||||
|
||||
switch {
|
||||
case ci.ContentType.Equal(oidDataContentType):
|
||||
if err := unmarshal(ci.Content.Bytes, &data); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
case ci.ContentType.Equal(oidEncryptedDataContentType):
|
||||
var encryptedData encryptedData
|
||||
if err := unmarshal(ci.Content.Bytes, &encryptedData); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if encryptedData.Version != 0 {
|
||||
return nil, nil, NotImplementedError("only version 0 of EncryptedData is supported")
|
||||
}
|
||||
if data, err = pbDecrypt(encryptedData.EncryptedContentInfo, password); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
default:
|
||||
return nil, nil, NotImplementedError("only data and encryptedData content types are supported in authenticated safe")
|
||||
}
|
||||
|
||||
var safeContents []safeBag
|
||||
if err := unmarshal(data, &safeContents); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
bags = append(bags, safeContents...)
|
||||
}
|
||||
|
||||
return bags, password, nil
|
||||
}
|
|
@ -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.
|
||||
|
||||
package pkcs12
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"encoding/asn1"
|
||||
"errors"
|
||||
)
|
||||
|
||||
var (
|
||||
// see https://tools.ietf.org/html/rfc7292#appendix-D
|
||||
oidCertTypeX509Certificate = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 9, 22, 1})
|
||||
oidPKCS8ShroundedKeyBag = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 10, 1, 2})
|
||||
oidCertBag = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 10, 1, 3})
|
||||
)
|
||||
|
||||
type certBag struct {
|
||||
Id asn1.ObjectIdentifier
|
||||
Data []byte `asn1:"tag:0,explicit"`
|
||||
}
|
||||
|
||||
func decodePkcs8ShroudedKeyBag(asn1Data, password []byte) (privateKey interface{}, err error) {
|
||||
pkinfo := new(encryptedPrivateKeyInfo)
|
||||
if err = unmarshal(asn1Data, pkinfo); err != nil {
|
||||
return nil, errors.New("pkcs12: error decoding PKCS#8 shrouded key bag: " + err.Error())
|
||||
}
|
||||
|
||||
pkData, err := pbDecrypt(pkinfo, password)
|
||||
if err != nil {
|
||||
return nil, errors.New("pkcs12: error decrypting PKCS#8 shrouded key bag: " + err.Error())
|
||||
}
|
||||
|
||||
ret := new(asn1.RawValue)
|
||||
if err = unmarshal(pkData, ret); err != nil {
|
||||
return nil, errors.New("pkcs12: error unmarshaling decrypted private key: " + err.Error())
|
||||
}
|
||||
|
||||
if privateKey, err = x509.ParsePKCS8PrivateKey(pkData); err != nil {
|
||||
return nil, errors.New("pkcs12: error parsing PKCS#8 private key: " + err.Error())
|
||||
}
|
||||
|
||||
return privateKey, nil
|
||||
}
|
||||
|
||||
func decodeCertBag(asn1Data []byte) (x509Certificates []byte, err error) {
|
||||
bag := new(certBag)
|
||||
if err := unmarshal(asn1Data, bag); err != nil {
|
||||
return nil, errors.New("pkcs12: error decoding cert bag: " + err.Error())
|
||||
}
|
||||
if !bag.Id.Equal(oidCertTypeX509Certificate) {
|
||||
return nil, NotImplementedError("only X509 certificates are supported")
|
||||
}
|
||||
return bag.Data, nil
|
||||
}
|
|
@ -11,8 +11,11 @@ contrib.go.opencensus.io/exporter/ocagent
|
|||
# github.com/1and1/oneandone-cloudserver-sdk-go v1.0.1
|
||||
github.com/1and1/oneandone-cloudserver-sdk-go
|
||||
# github.com/Azure/azure-sdk-for-go v30.0.0+incompatible
|
||||
github.com/Azure/azure-sdk-for-go/profiles/latest/compute/mgmt/compute
|
||||
github.com/Azure/azure-sdk-for-go/profiles/latest/compute/mgmt/compute/computeapi
|
||||
github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-04-01/compute
|
||||
github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-03-01/compute
|
||||
github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2019-03-01/compute/computeapi
|
||||
github.com/Azure/azure-sdk-for-go/services/network/mgmt/2018-01-01/network
|
||||
github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2016-06-01/subscriptions
|
||||
github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2018-02-01/resources
|
||||
|
@ -23,6 +26,8 @@ github.com/Azure/azure-sdk-for-go/version
|
|||
github.com/Azure/go-autorest/autorest
|
||||
github.com/Azure/go-autorest/autorest/adal
|
||||
github.com/Azure/go-autorest/autorest/azure
|
||||
github.com/Azure/go-autorest/autorest/azure/auth
|
||||
github.com/Azure/go-autorest/autorest/azure/cli
|
||||
github.com/Azure/go-autorest/autorest/date
|
||||
github.com/Azure/go-autorest/autorest/to
|
||||
github.com/Azure/go-autorest/autorest/validation
|
||||
|
@ -169,6 +174,8 @@ github.com/digitalocean/go-libvirt/internal/go-xdr/xdr2
|
|||
github.com/digitalocean/go-qemu/qmp
|
||||
# github.com/digitalocean/godo v1.11.1
|
||||
github.com/digitalocean/godo
|
||||
# github.com/dimchansky/utfbom v1.1.0
|
||||
github.com/dimchansky/utfbom
|
||||
# github.com/docker/docker v0.0.0-20180422163414-57142e89befe
|
||||
github.com/docker/docker/pkg/namesgenerator
|
||||
# github.com/dustin/go-humanize v1.0.0
|
||||
|
@ -605,6 +612,8 @@ golang.org/x/crypto/ed25519/internal/edwards25519
|
|||
golang.org/x/crypto/internal/chacha20
|
||||
golang.org/x/crypto/internal/subtle
|
||||
golang.org/x/crypto/md4
|
||||
golang.org/x/crypto/pkcs12
|
||||
golang.org/x/crypto/pkcs12/internal/rc2
|
||||
golang.org/x/crypto/poly1305
|
||||
golang.org/x/crypto/ssh
|
||||
golang.org/x/crypto/ssh/agent
|
||||
|
|
Loading…
Reference in New Issue